You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx反向代理Node.js文件上传时上游连接提前关闭问题求助

Nginx反向代理下Node.js应用文件上传超时问题

问题描述

部署在Nginx反向代理后的Node.js应用出现文件上传异常。当前架构使用Express-Formidable中间件处理文件上传,随后将文件上传至AWS S3存储桶。

具体表现:文件上传请求始终无法完成,API请求持续处理直至触发服务器超时,文件从未到达S3存储桶。其他API调用均正常,但涉及文件上传的请求会无限停滞。重启PM2进程后恢复正常,但一段时间后问题会再次出现。

Nginx错误日志

2024/09/04 18:32:44 [error] 63421#63421: *9345 , client: <my_ip>, server: <backend_api>, request: "POST /api/v1/video-project HTTP/2.0", upstream: "http://127.0.0.1:4000/api/v1/video-project", host: "<backend_api>", referrer: "<backend_api>"

Nginx相关配置

server {
    listen 443 ssl http2;
    client_max_body_size 600M;

    # Proxy settings for the main API
    location / {
        proxy_pass http://localhost:4000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_send_timeout 7200s;
        proxy_read_timeout 7200s;
        proxy_buffer_size 64k;
        proxy_buffers 16 32k;
        proxy_busy_buffers_size 64k;
        proxy_request_buffering off;
        proxy_buffering off;
        proxy_connect_timeout 300;
    }
}

疑问

  1. 有没有人遇到过Nginx在文件上传时提前关闭上游连接的类似问题?根本原因可能是什么?
  2. 这可能是Nginx配置问题,还是与Node.js的Express-Formidable包或AWS S3 SDK相关?
  3. 有哪些调试或解决该问题的建议?这是否与缓冲区设置或超时配置错误有关?

已尝试操作

  • 检查Nginx错误日志,未发现上述日志之外的其他内容。
  • 调整过client_max_body_size和代理相关配置,但问题仍存在。

问题解答

1. 类似问题与根本原因

这类上传超时且重启PM2恢复的情况,常见根本原因包括:

  • 上游连接泄漏:Node.js进程未正确释放文件上传相关的连接/资源,导致连接池耗尽,新请求无法被处理。
  • Express-Formidable资源泄漏:中间件未正确清理临时文件或内存,长期运行后导致进程资源占用过高,无法处理新的上传请求。
  • HTTP/2兼容性异常:当前Nginx启用HTTP/2,但反向代理到HTTP/1.1的Node.js服务,可能存在协议层面的连接复用问题。

2. 问题定位方向

大概率是Node.js侧的资源泄漏问题,而非单纯Nginx配置:

  • 若为Nginx配置问题,重启Nginx通常会生效,但你是重启PM2恢复,说明问题出在Node.js进程内。
  • Express-Formidable或AWS S3 SDK都可能导致泄漏:比如Formidable未处理上传中断的情况,临时文件堆积;S3上传未正确捕获错误,导致请求挂起占用连接。

3. 调试与解决建议

调试步骤
  • 监控Node.js进程资源:用pm2 monit查看CPU、内存变化,上传请求异常时是否出现资源飙升。
  • 增加Node.js日志:在Express中添加上传阶段的详细日志,记录Formidable接收文件、调用S3 SDK的各个节点,确认卡在接收文件阶段还是S3上传阶段。
  • 排查临时文件:检查Formidable默认的临时目录(通常是/tmp)是否存在大量未清理的文件,导致磁盘空间或inode耗尽。
配置与代码优化
  • 调整Nginx缓冲区设置:当前proxy_buffering off会让Nginx直接转发请求到上游,若上游处理慢,可能导致连接挂起。可尝试开启缓冲并调大参数:
    proxy_buffering on;
    proxy_buffer_size 128k;
    proxy_buffers 8 128k;
    proxy_busy_buffers_size 256k;
    
  • 优化Express-Formidable配置:显式设置临时目录、启用自动清理、限制文件大小:
    const formidable = require('express-formidable');
    const fs = require('fs');
    
    app.use(formidable({
      uploadDir: '/path/to/your/temp',
      keepExtensions: true,
      maxFileSize: 600 * 1024 * 1024, // 与Nginx的client_max_body_size匹配
      onError: (err, req, res) => {
        res.status(500).json({ error: err.message });
      },
      fileWriteStreamHandler: (file) => {
        const stream = fs.createWriteStream(file.path);
        stream.on('finish', () => {
          // 后续上传S3成功后删除临时文件
        });
        return stream;
      }
    }));
    
  • AWS S3上传异常处理:确保S3上传使用异步/await并正确捕获异常,避免请求挂起:
    const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3");
    const s3 = new S3Client({ region: 'your-region' });
    
    async function uploadToS3(file) {
      try {
        const command = new PutObjectCommand({
          Bucket: 'your-bucket',
          Key: file.name,
          Body: fs.createReadStream(file.path)
        });
        await s3.send(command);
        fs.unlinkSync(file.path); // 上传成功后清理临时文件
      } catch (err) {
        fs.unlinkSync(file.path); // 上传失败也清理临时文件
        throw err;
      }
    }
    
  • PM2进程监控重启:配置PM2自动重启规则,当内存占用超过阈值时自动重启,临时缓解问题:
    pm2 start app.js --max-memory-restart 500M
    

内容的提问来源于stack exchange,提问作者Ketan Jakhar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:57:32