需求背景
最近接了一些比较难搞的需求,主要任务是把单子关联的附件下载到本地,然后上传至文档库和ftp。这些文件原始出处有minio,有在集群之外的其他服务器。
上传过程要考虑不把系统打挂,控制好并发。
受制于网络环境,文件太大容易失败。
解决办法
- 采用node 快速开发。
- promise await 控制好并发
- 记录失败日志
- 和同事讨论后,采用分片上传,他给我shell脚本,我翻译成node
思路
- 获取唯一标识
- 获取文件md5值
- 采用split-file分割文件
- 循环分割文件上传
代码
// npm install crypto
// npm install request
// npm install split-file
const fs = require('fs');
const request = require('request');
const crypto = require('crypto');
const splitFile = require('split-file');
let repoId = 685;
let targetFilePath = "test/";
let artiName = "CentOS-7-x86_64-DVD-2009.iso";
// 文件路径
let fileName = "D:/vm/CentOS-7-x86_64-DVD-2009.iso";
let operationName = "石磊";
let artiType = 1;
let baseUrl = 'http://url'
// Split file size in MB
let fileSplitSize = 64;
function getChecksum(path) {
return new Promise(function (resolve, reject) {
// crypto.createHash('sha1');
// crypto.createHash('sha256');
const hash = crypto.createHash('md5');
const input = fs.createReadStream(path);
input.on('error', reject);
input.on('data', function (chunk) {
hash.update(chunk);
});
input.on('close', function () {
resolve(hash.digest('hex'));
});
});
}
console.log("current file_split_size: " + fileSplitSize);
// Get upload identity
request.post({
url: baseUrl + '/uuid',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ 'repoId': repoId })
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
let identityResult = JSON.parse(body);
let identity = identityResult.data;
console.info('identity: ', identity);
let splitFilePromise = splitFile.splitFileBySize(fileName, fileSplitSize * 1024 * 1024);
let md5Promise = getChecksum(fileName);
Promise.all([md5Promise, splitFilePromise])
.then(async results => {
let md5 = results[0];
let names = results[1];
for (let i = 0; i < names.length; i++) {
let tempPath = names[i];
console.log("tempPath: ", tempPath);
let formData = {
chunk: i,
chunks: names.length,
name: artiName,
md5: md5,
identity: identity,
repoId: repoId,
targetFilePath: targetFilePath,
artiName: artiName,
artiType: artiType,
operationName: operationName,
file: {
value: fs.createReadStream(tempPath),
options: {
filename: 'nameinpost',
contentType: 'multipart/form-data'
}
}
};
try {
await uploadFileChunk(formData);
} catch (err) {
console.error(err);
}
}
})
.catch(err => {
console.log(err);
});
}
});
async function uploadFileChunk(formData) {
console.log("start -formData: ", formData);
return new Promise((resolve, reject) => {
request.post({
url: baseUrl + '/api/uploadurl',
formData: formData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
let result = JSON.parse(body).data;
console.log("Link: " + result);
resolve(result);
} else {
console.log("Error from: ", formData);
console.error("Error: ", error);
reject(error);
}
});
});
}
总结
放弃问题就没收获!