背景

两台外网服务器之间需要传输一个较大的文件,目标服务器有webserver。

解决方案

初步想了下,有几种思路:

  • ftp:目标服务器搭建ftp。通过ftp client上传。部署成本太高(主要是懒),放弃
  • nginx-upload-module: 较为理想的方案,使用nginx插件支持,成本小。但在编译module时卡住了,忘了之前的编译选项,加入upload module之后编译又报错,不想太折腾,放弃了。
  • 在webserver上自己实现file upload server:此方案看似成本高,翻了一下,其实还挺简单。那就动手吧

流程

http upload server搭建

方法有很多,搭建webserver第一个想到的就是node了。于是找到了express-fileupload。npm库上代码都是现成的。


const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();

// default options
app.use(fileUpload());

app.post('/upload', function(req, res) {
if (!req.files)
return res.status(400).send('No files were uploaded.');

// The name of the input field (i.e. "sampleFile") is used to retrieve the uploaded file
let sampleFile = req.files.sampleFile;

// Use the mv() method to place the file somewhere on your server
sampleFile.mv('/somewhere/on/your/server/filename.jpg', function(err) {
if (err)
return res.status(500).send(err);

res.send('File uploaded!');
});
});

// app.listen(8080);

nginx路由

反向代理增加路由配置:

location /upload {
proxy_pass http://127.0.0.1:5000;
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;
}

并设置最大包大小,否则文件过大会被ng拒绝413 (Request Entity Too Large)

client_max_body_size       200m;

上传

使用curl模拟表单上传:

curl -F 'sampleFile=@path/to/local/file' UPLOAD_ADDRESS

curl支持一次上传多个,不过upload server实现得修改支持命名。

其他

线上上传时发现上传还是失败了,因为文件太大,导致node进程OOM kill了。。
不想在折腾了,直接用split把文件切成几个小文件后上传,然后再到目标机器使用cat合并。

# binary拆分成多个20m的文件,输出文件名类似outputSerial_aa, outputSerial_ab, outputSerial_ac....
split -b 20m uploadfile outputSerial_

在目标机器执行合并操作:

cat outputSerial_* > uploadfile

总结起来,对比重编ng貌似也不简单:P)。。