gpt4 book ai didi

php - Nginx PHP 因大文件上传(超过 6 GB)而失败

转载 作者:行者123 更新时间:2023-12-02 21:28:08 26 4
gpt4 key购买 nike

我在上传超过 6GB 的大文件时遇到一个非常奇怪的问题。我的流程是这样的:

  1. 文件通过 Ajax 上传到 PHP 脚本。
  2. PHP 上传脚本获取 $_FILE 并将其分块复制,如 this answer 所示。到临时位置。
  3. 文件的位置存储在数据库中
  4. cron 脚本稍后会将文件上传到 s3,再次使用 fopen 函数和缓冲来保持较低的内存使用量

我的 PHP(HHVM) 和 NGINX 配置都将其配置设置为允许最多 16GB 的文件,我的测试文件只有 8GB。

这是奇怪的部分,ajax总是超时。但是文件已成功上传,它被复制到 tmp 位置,即存储在 db、s3 等中的位置。但是即使在所有执行完成之后,AJAX 也会运行一个小时(这需要 10-15 分钟) )并且仅在超时时结束。

什么可能导致服务器不发送仅对大文件的响应?

服务器端的错误日志也是空的。

最佳答案

大文件上传是一项昂贵且容易出错的操作。 Nginx 和后端应该配置正确的超时来处理缓慢的磁盘 IO(如果发生)。理论上,使用多部分/表单数据编码 RFC 1867 管理文件上传非常简单。

根据developer.mozilla.org在 multipart/form-data 正文中,HTTP Content-Disposition 通用 header 是可在多部分正文的子部分上使用的 header ,以提供有关其适用的字段的信息。子部分由 Content-Type header 中定义的边界分隔。用于正文本身,Content-Disposition 没有任何效果。

让我们看看文件上传时发生了什么:

1) 客户端向网络服务器发送带有文件内容的 HTTP 请求

2) Web服务器接受请求并启动数据传输(如果文件大小超过限制,则返回错误413)

3) 网络服务器开始填充缓冲区(取决于文件和缓冲区大小)

4)网络服务器通过文件/网络套接字将文件内容发送到后端

5) 后端验证初始请求

6)后端读取文件并剪切头部(Content-Disposition、Content-Type)

7) 后端将结果文件转储到磁盘

8) 任何后续程序,例如数据库更改

client_body_in_file_only off;

在大文件上传过程中会出现一些问题:

  • HTTP 正文请求转储到磁盘并传递到后端处理和复制文件
  • 在 HTTP 请求内容上传到服务器之前无法验证请求
  • 虽然上传大文件后端很少需要立即获取文件内容

让我们从配置新位置的 Nginx 开始 http://backend/upload 为了接收大文件上传,后端交互被最小化(Content-Legth:0),文件仅存储到磁盘。使用缓冲区 Nginx 将文件转储到磁盘(文件存储到临时目录中,名称随机,无法更改),然后向后端发送 POST 请求到位置 http://backend/file X-File-Name header 中的文件名。

要保留额外信息,您可以在初始 POST 请求中使用 header 。例如,初始请求中的 X-Original-File-Name header 可帮助您匹配文件并将必要的映射信息存储到数据库。

client_body_in_file_only on;

让我们看看如何实现它:

1) 配置 Nginx 将 HTTP 正文内容转储到文件并将其存储在client_body_in_file_only;

2) 创建新的后端端点 http://backend/file处理临时文件名和 header X-File-Name

之间的映射

4) 带有 header X-File-Name 的仪器 AJAX 查询,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 configuration option client_body_in_file_only is incompatible with multi-part data upload, but you can use it with AJAX i.e. XMLHttpRequest2 (binary data).

如果需要后端验证,唯一的处理方法是使用auth_request ,例如:

location = /upload {
auth_request /upload/authenticate;
...
}

location = /upload/authenticate {
internal;
proxy_set_body off;
proxy_pass http://backend;
}

client_body_in_file_only on; auth_request on;

无论初始 POST 内容长度大小如何,预上传身份验证逻辑都会防止未经身份验证的请求。

关于php - Nginx PHP 因大文件上传(超过 6 GB)而失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44371643/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com