【问题标题】:Nginx node.js express download big files stop at 1.08GBNginx node.js express下载大文件停止在1.08GB
【发布时间】:2014-09-22 06:39:39
【问题描述】:

我有这个由 Nginx 代理的 node.js 应用程序(在生产中)。路线是这样的:

exports.download = function(req, res){

    var id = req.params.id;

    if (id && id == 'latest')
    {
        res.download(config.items.release_directory+'/<1.6GB-file>.zip', function(err){
            if (err) {
                console.log(err);
            } else {
                // do something
            }
        });
    }
    else
    {
        res.redirect(301, '/');
    }

};

因此,单击正确的路由/URL,浏览器开始下载大文件,但随后它总是停止在 1.08GB(文件大约为 1.6GB),将其截断。

我真的不明白为什么。有什么想法吗?

编辑: config.items.release_directory 是一个静态 Express 目录,声明为:

app.use('/releases', express.static(path.join(__dirname, '..', 'releases')));

编辑2: 在没有 Nginx 的情况下,使用 grunt 直接为应用程序提供服务的开发工作正常。

已解决:阅读下面的 cmets,问题是 Nginx 中的 proxy_max_temp_file_size 变量

【问题讨论】:

  • 另一个奇怪的行为是:如果我从浏览器单击 url,它会发生这种情况,但如果我 curl/wget URL,我可以完全接收文件。

标签: javascript node.js file express nginx


【解决方案1】:

这里问题是nginx配置,不是nodejs代码。

nginx 在将临时文件发送到客户端之前将它们写入磁盘,如果站点要提供大型静态文件,通常最好禁用此缓存,例如:

location / {
    proxy_max_temp_file_size 0;
}

(无限制)

【讨论】:

  • 这似乎是一个令人信服的“修复”,但也会通过消耗所有可用内存打开导致 NGINX 进程崩溃的大门,不是吗? @Rémi Becheras
【解决方案2】:

如果在使用 Nginx 代理时上传文件,您可以在 Nginx 配置中的 server{} 块内设置“最大正文大小”:

client_max_body_size 0; # disable any limits to avoid HTTP 413

如果您收到HTTP 413,请检查您的 Nginx 配置并相应地将其设置为零或启动它。

否则,我会尝试增加一些超时时间,例如:

send_timeout 600s; # default is 60s; context: http, server, location

proxy_read_timeout 600s; # default is 60s; context: http, server, location
proxy_send_timeout 600s; # default is 60s; context: http, server, location

有关更多代理选项,请查看 Nginx 代理模块文档 (link)。

【讨论】:

  • 嗯,我想我在 Nginx 中设置的这个参数默认为 1GB "proxy_max_temp_file_size" nginx.org/en/docs/http/… 我认为增加它可以解决问题。
  • 啊.. 但是,如果您将proxy_max_temp_file_size 设置为.. 说.. 1MB,您是说您的下载也会停止在 1MB 吗? Nginx 文档似乎实际上暗示了它。我可以看到这可能是正确的行为,但我希望文档提供一个示例来描述大文件下载的潜在问题..
  • 做到了,但你是对的我不知道我现在设置的如此大的临时文件大小会发生什么。可能最好的方法是在不代理下载目录的情况下提供下载目录。
  • @anapsix 实际上这种行为比这更微妙一些。在我们的例子中,nodejs 中默认的 HTTP 服务器套接字超时是两分钟。当代理临时文件填满时,nginx 停止从 nodejs 服务器套接字读取,直到它已将 所有 的缓存数据传送到其 HTTP 客户端。如果这比 nodejs HTTP 服务器超时时间长,那么连接 nginxnodejs 会被 nodejs 关闭,并且 nginx 将简单地完成它在缓存文件中的内容,然后关闭与 HTTP 客户端的连接。
  • @anapsix 所以正确的推理方法是,如果 1GB 的数据无法传送到 HTTP客户端在两分钟内,他们只会得到 1GB。 这意味着降低 提高 nginx 中的最大临时文件大小可以解决问题! 提高它以适应 nodejs 的整个响应将解决它。同样,将它降低到 1MB 可以解决它,只要 nginx 可以在两分钟内将 1MB 推送到其 HTTP 客户端!当然,禁用临时文件也可以修复它。
【解决方案3】:

强烈不鼓励设置 proxy_max_temp_file_size 0,因为这会删除所有端点的任何代理缓冲区。

这意味着您的应用程序服务器将无法将响应数据刷新到 NGINX 缓冲区(下游客户端只要获得足够的连接就可以从中读取)并被释放/解除阻塞。相反,您的应用服务器将等待客户端(中间没有 NGINX 代理)下载数据。

或者,您可以指示您的 NGINX 代理在流式传输您的 zipfile 数据时选择性地不缓冲响应数据,以避免 NGINX 的缓冲区临时文件变满和中断流式下载的任何潜在问题(这是我的经验) .

您可以通过在 Node.js 端点中执行以下操作来实现此目的:

res.set('X-Accel-Buffering', 'no');

这样,数据将直接从 Express 流式传输到客户端,但仅用于您不希望缓冲响应数据的端点(很可能是您的流式传输端点)。

【讨论】:

    【解决方案4】:

    在我的例子中,我必须设置proxy_request_buffering off; 这可以确保在客户端连接缓慢的情况下不会缓冲数据。这样做的副作用是,这会禁用一些我没有使用的 nginx 功能,例如 $request_body

    【讨论】:

      猜你喜欢
      • 2016-06-08
      • 1970-01-01
      • 2021-10-13
      • 2019-08-20
      • 1970-01-01
      • 2021-10-20
      • 2019-01-11
      • 2015-02-10
      • 1970-01-01
      相关资源
      最近更新 更多