Javascript 通过服务器将多个文件上载到S3时,如何从故障中恢复?

Javascript 通过服务器将多个文件上载到S3时,如何从故障中恢复?,javascript,node.js,amazon-s3,busboy,Javascript,Node.js,Amazon S3,Busboy,刚接触NodeJS和S3时,我编写了以下探索性代码,通过我的NodeJS服务器将文件上载到S3,而无需将文件保存到磁盘或内存: var express = require('express'); var Busboy = require('busboy'); var S3 = require('../utils/s3Util'); var router = express.Router(); // mounted at /uploads router.post("/", function (r

刚接触NodeJS和S3时,我编写了以下探索性代码,通过我的NodeJS服务器将文件上载到S3,而无需将文件保存到磁盘或内存:

var express = require('express');
var Busboy = require('busboy');
var S3 = require('../utils/s3Util');
var router = express.Router(); // mounted at /uploads

router.post("/", function (req, res, next) {
    let bb = new Busboy({ headers: req.headers });
    const uploads = [];
    bb.on('file', (fieldname, stream, filename, encoding, mimeType) => {
        console.log(`Uploaded fieldname: ${fieldname}; filename: ${filename}, mimeType: ${mimeType}`);
        uploads.push(S3.svc.upload({ Bucket: 'my-test-bucket', Key: filename, Body: stream }).promise());
    });
    bb.on('finish', () => {
        console.log("# of promises:", uploads.length);
        Promise.all(uploads).then(retVals => {
            for (let i = 0; retVals && i < retVals.length; i++) {
                console.log(`File ${i + 1}::`, retVals[i]); 
            }
            res.end();
        }).catch(err => {
            console.log("Error::", err);
            res.status(500).send(`${err.name}: ${err.message}`);
        });
    });
    req.pipe(bb);
});

module.exports = router;
var express=require('express');
var-Busboy=需要(“Busboy”);
var S3=require('../utils/s3Util');
var router=express.router();//装载/上传
router.post(“/”,函数(请求、恢复、下一步){
设bb=new-Busboy({headers:req.headers});
const uploads=[];
bb.on('file',(字段名、流、文件名、编码、mimeType)=>{
log(`upload fieldname:${fieldname};filename:${filename},mimeType:${mimeType}`);
uploads.push(S3.svc.upload({Bucket:'my test Bucket',Key:filename,Body:stream}).promise());
});
bb.on('finish',()=>{
console.log(“#of promises:”,uploads.length);
Promise.all(上传)。然后(retVals=>{
对于(设i=0;retVals&&i{
log(“错误::”,err);
res.status(500).send(`${err.name}:${err.message}`);
});
});
所需管道(bb);
});
module.exports=路由器;
在一般失败的情况下,如何处理上载1个或多个x文件失败的情况?有些上传会成功,有些会失败。然而,在
catch
子句中,我不知道哪些失败了


最好能使这个上传过程有点事务性(即,要么所有上传成功,要么没有成功)。当出现错误时,理想情况下我能够“回滚”成功上载的子集。

您可以这样做:

将一个对象推送到上载中,其中包含需要重试的数据,因此:

uploads.push({ 
  fieldname, 
  filename, 
  mimeType,
  uploaded: S3.svc.upload({ Bucket: 'my-test-bucket', Key: filename, Body: stream })
    .promise()
    .then(() => true)
    .catch(() => false)
});

...

const failed = await 
  (Promise.all(uploads.map(async upload => ({...upload, uploaded: await upload.uploaded})))).then(u => u.filter(upload => !upload.uploaded))

const failedFiles = failed.join(', ')

console.log(`The following files failed to upload: ${failedFiles}`);
您需要使事件处理程序
async
在它们内部使用
wait
,例如:

bb.on('file', async (fieldname, stream, filename, encoding, mimeType) => {

你可以这样做:

将一个对象推送到上载中,其中包含需要重试的数据,因此:

uploads.push({ 
  fieldname, 
  filename, 
  mimeType,
  uploaded: S3.svc.upload({ Bucket: 'my-test-bucket', Key: filename, Body: stream })
    .promise()
    .then(() => true)
    .catch(() => false)
});

...

const failed = await 
  (Promise.all(uploads.map(async upload => ({...upload, uploaded: await upload.uploaded})))).then(u => u.filter(upload => !upload.uploaded))

const failedFiles = failed.join(', ')

console.log(`The following files failed to upload: ${failedFiles}`);
您需要使事件处理程序
async
在它们内部使用
wait
,例如:

bb.on('file', async (fieldname, stream, filename, encoding, mimeType) => {

我最后使用了以下代码,这是@JoshWulf答案的扩展:

function handleUpload(req, res, bucket, key) {
    let bb = new Busboy({ headers: req.headers });
    const uploads = [];
    bb.on('file', (fieldname, stream, filename, encoding, mimeType) => {
        console.log(`Uploaded fieldname: ${fieldname}; filename: ${filename}, mimeType: ${mimeType}`);
        const params = { Bucket: bucket, Key: key, Body: stream, ContentType: mimeType };
        uploads.push({ filename, result: S3.svc.upload(params).promise().then(data => data).catch(err => err) });
    });
    bb.on('finish', async () => {
        const results = await Promise.all(uploads.map(async (upload) => ({ ...upload, result: await upload.result })));
        // handle success/failure with their respective objects
    });
    req.pipe(bb);
}

这里与@answer的区别在于,在我的上传承诺中,我将按原样返回返回返回的数据对象(如果成功)和返回的错误对象(如果失败)。这使我以后可以根据需要使用它们。

我最终使用了以下代码,这是@JoshWulf答案的扩展:

function handleUpload(req, res, bucket, key) {
    let bb = new Busboy({ headers: req.headers });
    const uploads = [];
    bb.on('file', (fieldname, stream, filename, encoding, mimeType) => {
        console.log(`Uploaded fieldname: ${fieldname}; filename: ${filename}, mimeType: ${mimeType}`);
        const params = { Bucket: bucket, Key: key, Body: stream, ContentType: mimeType };
        uploads.push({ filename, result: S3.svc.upload(params).promise().then(data => data).catch(err => err) });
    });
    bb.on('finish', async () => {
        const results = await Promise.all(uploads.map(async (upload) => ({ ...upload, result: await upload.result })));
        // handle success/failure with their respective objects
    });
    req.pipe(bb);
}

这里与@answer的区别在于,在我的上传承诺中,我将按原样返回返回返回的数据对象(如果成功)和返回的错误对象(如果失败)。这使我以后可以根据需要使用它们。

非常有趣的解决方案,谢谢!
文件
事件的处理程序的签名不是由
busboy
模块指定的吗(我对Javascript还很陌生,不确定这一点)?看:真实的故事,没有想到这一点-这不是你的API,所以你必须用它!非常有趣的解决方案,谢谢!
文件
事件的处理程序的签名不是由
busboy
模块指定的吗(我对Javascript还很陌生,不确定这一点)?看:真实的故事,没有想到这一点-这不是你的API,所以你必须用它!很好的解决方案!干得好。这将有助于未来的人。很好的解决方案!干得好。这将在将来帮助某人。