我有一个非常奇怪的问题上传大于6GB的大文件。 我的过程是这样的:
我的PHP(HHVM)和NGINXconfiguration都configuration为允许高达16GB的文件,我的testing文件只有8GB。
这是怪异的部分,阿贾克斯总是会超时。 但是文件已经成功上传了,它被拷贝到了tmp的位置,存储在db,s3等等的位置。但是AJAX运行了一个小时,甚至在所有的执行完成之后(需要10-15分钟)超时时结束。
什么可以导致服务器不发送大文件的响应?
另外服务器端的错误日志是空的。
一个大文件上传是昂贵的和容易出错的操作。 Nginx和后端应该有正确的超时边界来处理缓慢的磁盘IO(如果有的话)。 从理论上讲,使用多部分/表单数据编码RFC 1867来管理文件上传是非常简单的。
根据developer.mozilla.org中的多部分/表单数据体,HTTP Content-Disposition一般头部是一个头部,可以在多部分主体的子部分上使用,以提供有关应用的字段的信息。 子部分由Content-Type头部中定义的边界分隔。 对于身体本身,Content-Disposition没有任何作用。
让我们看看文件上传时会发生什么:
1)客户端发送带有文件内容的HTTP请求到Web服务器
2)web服务器接受请求并启动数据传输(如果文件大小超过限制,则返回错误413)
3)Web服务器开始填充缓冲区(取决于文件和缓冲区的大小)
4)网络服务器通过文件/网络套接字将文件内容发送到后端
5)后端验证初始请求
6)后端读取文件并剪切标题(Content-Disposition,Content-Type)
7)后端转储结果文件到磁盘上
8)任何后续程序,如数据库更改
在大文件上传期间会出现几个问题:
让我们从配置了新位置http:// backend / upload的 Nginx开始接收大文件上传,后端交互被最小化(Content-Legth:0),文件正在存储到磁盘。 使用缓冲区Nginx将文件转储到磁盘(一个文件存储到临时目录,随机的名称,它不能被改变)后面的POST请求后端到位置http://后端/文件的文件名在X-File-名称标题。
要保留额外的信息,您可以使用包含初始POST请求的标头。 例如,从最初的请求中获得X-Original-File-Name头文件可以帮助您匹配文件并将必要的映射信息存储到数据库中。
让我们看看是如何发生的:
1)配置Nginx将HTTP正文内容转储到文件并保存client_body_in_file_only;
2)创建新的后端端点http://后端/文件来处理临时文件名和标题之间的映射X-File-Name
4)仪器带头文件的 AJAX查询X-File-Name Nginx将使用发送文件上传请求
组态:
location /upload { client_body_temp_path /tmp/; client_body_in_file_only on; client_body_buffer_size 1M; client_max_body_size 7G; proxy_pass_request_headers on; proxy_set_header X-File-Name $request_body_file; proxy_set_body off; proxy_redirect off; proxy_pass http://backend/file; }
Nginx配置选项client_body_in_file_only与多部分数据上传不兼容,但是可以使用AJAX即XMLHttpRequest2(二进制数据)。
如果您需要进行后端身份验证,则唯一的办法就是使用auth_request ,例如:
location = /upload { auth_request /upload/authenticate; ... } location = /upload/authenticate { internal; proxy_set_body off; proxy_pass http://backend; }
预先上传身份验证逻辑可防止未经身份验证的请求,而不管初始POST内容长度大小。