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; } }
疑问
- 有没有人遇到过Nginx在文件上传时提前关闭上游连接的类似问题?根本原因可能是什么?
- 这可能是Nginx配置问题,还是与Node.js的Express-Formidable包或AWS S3 SDK相关?
- 有哪些调试或解决该问题的建议?这是否与缓冲区设置或超时配置错误有关?
已尝试操作
- 检查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
相关产品推荐
相关产品推荐

