我有一个非常奇怪的问题,上传超过6GB的大文件。我的流程是这样的:
我的PHP(HHVM)和NGINX配置都将其配置设置为允许最多16GB的文件,我的测试文件只有8GB。
这是奇怪的部分,ajax将总是超时。但是文件成功上传,它被复制到tmp位置,存储在db,s3等位置。但是AJAX运行了一个小时甚至所有执行完成后(需要10-15分钟) )并且仅在超时时结束。
什么原因导致服务器不能仅为大文件发送响应?
服务器端的错误日志也是空的。
答案 0 :(得分:41)
大文件上传是一项昂贵且容易出错的操作。 Nginx和后端应配置正确的超时,以便在发生时处理慢速磁盘IO。从理论上讲,使用multipart / form-data encoding RFC 1867来管理文件上传是很简单的。
根据multipart / form-data主体中的developer.mozilla.org,HTTP Content-Disposition通用标头是一个标头,可以在多部分主体的子部分上使用,以提供有关其应用的字段的信息。子部分由Content-Type标头中定义的边界分隔。用于身体本身,Content-Disposition无效。
让我们看看上传文件时会发生什么:
1)客户端将带有文件内容的HTTP请求发送到webserver
2)webserver接受请求并启动数据传输(如果文件大小超过限制,则返回错误413)
3)webserver开始填充缓冲区(取决于文件和缓冲区大小)
4)webserver通过文件/网络套接字将文件内容发送到后端
5)后端验证初始请求
6)后端读取文件并剪切标题(Content-Disposition,Content-Type)
7)后端转储导致文件到磁盘
8)任何后续程序,如数据库更改
在大文件上传期间会出现几个问题:
让我们从配置了新位置 http://backend/upload 的Nginx开始接收大文件上传,最小化后端交互(Content-Legth:0),文件正在存储到磁盘。使用缓冲区Nginx将文件转储到磁盘(存储到临时目录中的文件具有随机名称,无法更改),然后POST请求后端到文件名为 http://backend/file 的位置在 X-File-Name 标题中。
要保留额外信息,您可以使用带有初始POST请求的标头。例如,从初始请求中获取 X-Original-File-Name 标头可帮助您匹配文件并将必要的映射信息存储到数据库中。
让我们看看它是如何实现的:
1)配置Nginx将HTTP正文内容转储到文件并保存 client_body_in_file_only on;
2)创建新的后端端点http://backend/file来处理临时文件名和标题之间的映射 X-File-Name
4)具有标题 X-File-Name 的工具AJAX查询Nginx将使用
发送上传后请求配置:
let
Nginx配置选项client_body_in_file_only是 与多部分数据上传不兼容,但您可以将其与AJAX一起使用 即XMLHttpRequest2(二进制数据)。
如果您需要进行后端身份验证,则只能使用auth_request,例如:
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;
}
无论初始POST内容长度大小如何,预上载身份验证逻辑都可以防止未经身份验证的请求。