nginx node.js 上传大文件时出现502 Bad Gateway
发布于 7 年前 作者 willmynew 8966 次浏览 来自 问答

环境 ubuntu 14.04 nginx 1.10.2 node.js 0.10.32 express 3.5.1 sequelize 1.7.0 设置了最大连接数

	pool: {
      maxConnections: 1000,
      maxIdleTime: 30
    }

mysql 5.5

我遇到的问题:

  1. 在使用nginx做反向代理时: 当文件小于100M时 上传成功 当文件大于100M时 上传失败 前端收到502 Bad Gateway 后端node.js报错mysql too many connections
  2. 不使用nginx直接访问 任意文件都可以上传成功

我所查到的最类似与我的问题为 502 Bad Gateway with “large” file uploads

现阶段我所做的工作 根据网上查询到方法,修改nginx的配置 加上了如下的 在http模块中加入

    keepalive_timeout  600;
    send_timeout 10m;
    client_header_timeout 10m;
    client_body_timeout 10m;
    client_max_body_size 512m;
    large_client_header_buffers 8 32k;

在server中加入

 	client_max_body_size 512m;
    proxy_buffer_size 512k;
    proxy_buffers 4 1024k;
    proxy_busy_buffers_size 1024k;

其中这部分的配置将512k修改为128k 1024k修改为256k 有成功过一次 完整的nginx.conf文件如下

	user  root root;
	worker_processes  6;
	worker_cpu_affinity 000000000000000000000001 000000000000000000000010 000000000000000000000100 000000000000000000001000 000000000000000000010000 000000000000000000100000;
	worker_rlimit_nofile 65530;
	events {
		worker_connections  65530;
	}
	http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    tcp_nopush     on;
    tcp_nodelay on; 
    #keepalive_timeout  0;
    keepalive_timeout  600;
    send_timeout 10m;
    client_header_timeout 10m;
    client_body_timeout 10m;
    client_max_body_size 512m;
    large_client_header_buffers 8 32k;
    gzip  on;
    upstream tvbox {
        server 127.0.0.1:9123;
    }
    server {
        listen       80;
        server_name  myip;
        client_max_body_size 512m;
        proxy_buffer_size 512k;
        proxy_buffers 4 1024k;
        proxy_busy_buffers_size 1024k;
        location / {
                keepalive_timeout 600;
                proxy_set_header   X-Real-IP            $remote_addr;
                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
                proxy_set_header   Host                   $host;
                proxy_set_header   X-NginX-Proxy    true;
                proxy_set_header   Connection "";
                proxy_http_version 1.1;
                proxy_pass         http://tvbox;
                proxy_redirect off;
        }
        location ~ ^/(softwares|ad|images_activity|images_recommends|images_film|images_screen_protector|apk_dir|app_shop_dir)/  {
                root    /uploads;
                autoindex on;
                autoindex_exact_size off;
                autoindex_localtime on;
         }
    }
	}

node.js中的接收上传文件的部分代码如下

     module.exports.uploadfile = function (req, res) {
	 var software_version = {};
    var source = req.files.uploadingfile.path;
    var size = req.files.uploadingfile.size;
    var minetype = req.files.uploadingfile.type;
    var suffix = getExtension(req.files.uploadingfile.name);
    software_version.minetype = minetype;
    async.series([
        // 计算文件HASH
        function(callback){
            var sha1 = crypto.createHash('sha1');
            var s = fs.ReadStream(source);
            s.on('data', function (d) {
                sha1.update(d);
            });
            s.on('end', function () {
                var hash = sha1.digest('hex');
                callback(null, hash);
            });
        },
        // 获取文件大小
        function(callback){
            fs.stat(source, function(err, stats){
                if(err) throw err;
                callback(null, stats.size);
            });
        }
    ], function(err, results){
        var hash = results[0];
        var size = results[1];
		//查询数据库中是否有记录
        db.software_version.find({
            where: {
                id: req.body.id
            }
        }).success(function(item){
            if(item == null)
            {
                // 创建
                db.software_version.create({
                    hash: hash,
                    size: size,
                    suffix: suffix,
                    minetype: minetype,
                    url: '/softwares/'+hash+suffix
                }).success(function (software_version) {
                    res.json({
                        status: 'ok',
                        result: software_version
                    });
                }).failure(function (error) {
                    res.json({
                        status: 'error',
                        result: {
                            msg: '数据库错误,请联系管理员'
                        }
                    })
                });
            }else{
                // 更新
                db.software_version.update({
                    hash: hash,
                    size: size,
                    suffix: suffix,
                    minetype: minetype,
                    url: '/softwares/'+hash+suffix
                }, {
                    id: item.id
                }).success(function (affected_rows) {
                    db.software_version.find(item.id).success(function(row){
                        res.json({
                            status: 'ok',
                            result: row.dataValues
                        });
                    });
                }).failure(function (error) {
                    res.json({
                        status: 'error',
                        result: {
                            msg: '数据库错误,请联系管理员'
                        }
                    })
                });;
            }
        });
    });
     };

最后求各位大神看下能否有什么办法解决这个问题

7 回复

调整nginx的http超时以及最大允许的body size。

@stonephp client_header_timeout client_body_timeout keepalive_timeout 都有设置过600 client_max_body_size也有设置为512m

检查一下你的环境是不是用nginx代理了多次

@willmynew upload file 也调大

谢谢各位 问题找到了 是sequelize的问题 我的理解为 当连接时间超过指定时间 sequelize就自动报错了 我修改了sequelize的pool设置 文件就可以上传成功了

@willmynew 应该实现断点续传功能,不应该这么大的文件直接上传,将文件分片上传,比如一片1M

来自酷炫的 CNodeMD

有上网搜过,有动手测试,这才是提问的正确姿势

回到顶部