1

如标题所示,我目前正在使用sailjs+skipper-better-s3进行 s3 上传。从上传一个效果很好的文件开始,然后因为更改请求需要一次上传多个文件,所以我添加了一个for循环,但是通过这样做,所有键都将是相同的,最后只上传了一个文件,即最后上传的文件,但第一个上传的文件名。

我确实读过一些文章,人们在说类似的事情The problem is because for loop is synchronous and file upload is asynchronous,人们说这样做的结果是使用我也尝试过的递归,但没有运气,同样的事情发生了。

我的递归代码如下...

s3_upload_multi: async (req, res) => {
    const generatePath = (rootPath, fieldName) => {
        let path;
        // this is just a switch statement here to check which fieldName is provided then value of path will depend on it
        // as for the other two variable is just checking if upload content type is correct
        return { path };
    };

    const processUpload = async ({
        fieldName,
        awsOp,
        fileExtension,
        rootPath,
        fileName,
    }) => {
        return new Promise(function (resolve, reject) {
            req.file(fieldName).upload(awsOp, async (err, filesUploaded) => {
                if (err) reject(err);
                const filesUploadedF = filesUploaded[0]; // F = first file
                const response = {
                    status: true,
                    errCode: 200,
                    msg: 'OK',
                    response: {
                        url: filesUploadedF.extra.Location,
                        size: filesUploadedF.size,
                        type: fileExtension,
                        filename: filesUploadedF.filename,
                        key: filesUploadedF.extra.Key,
                        field: fieldName,
                    }
                };

                resolve(response);
            });
        });
    }

    const process_recur = async (files, fieldName) => {
        if (files.length <= 0) return;
        const fileUpload = files[0].stream;
        const rootPath = `${sails.config.aws.upload.path.root}`;
        const fileCType = fileUpload.headers['content-type'];
        // console.log(fileCType, 'fileCType');

        const { path } = generatePath(rootPath, fieldName);

        const fileName = fileUpload.filename;

        const fileExtension = fileUpload.filename.split('.').pop();

        const genRan = await UtilsService.genRan(8);
        const fullPath = `${path}${genRan}-${fileName}`;
        const awsOp = {
            adapter: require('skipper-better-s3'),
            key: sails.config.aws.access_key,
            secret: sails.config.aws.secret_key,
            saveAs: fullPath,
            bucket: sails.config.aws.bucket,
            s3params: {
                ACL: 'public-read'
            },
        };

        const config = {
            fieldName,
            awsOp,
            fileExtension,
            rootPath,
            fileName,
        }

        const procceed = await processUpload(config);
        files.shift();
        await process_recur(files, fieldName);
    };

    try {
        const fieldName = req._fileparser.upstreams[0].fieldName;
        const files = req.file(fieldName)._files;
        await process_recur(files, fieldName);
    } catch (e) {
        console.log(e, 'inside UploadService');
        return false;
    }
}

下面是我使用 for 循环的代码,它与上面非常相似

s3_upload_multi: async (req, res) => {
    const generatePath = (rootPath, fieldName) => {
        let path;
        // this is just a switch statement here to check which fieldName is provided then value of path will depend on it
        // as for the other two variable is just checking if upload content type is correct
        return { path };
    };

    const processUpload = async ({
        fieldName,
        awsOp,
        fileExtension,
        rootPath,
        fileName,
    }) => {
        return new Promise(function (resolve, reject) {
            req.file(fieldName).upload(awsOp, async (err, filesUploaded) => {
                if (err) reject(err);
                const filesUploadedF = filesUploaded[0]; // F = first file
                const response = {
                    status: true,
                    errCode: 200,
                    msg: 'OK',
                    response: {
                        url: filesUploadedF.extra.Location,
                        size: filesUploadedF.size,
                        type: fileExtension,
                        filename: filesUploadedF.filename,
                        key: filesUploadedF.extra.Key,
                        field: fieldName,
                    }
                };

                resolve(response);
            });
        });
    }

    try {
        const fieldName = req._fileparser.upstreams[0].fieldName;
        const files = req.file(fieldName)._files;

        for (const file of files) {
            const fileUpload = file.stream;
            const rootPath = `${sails.config.aws.upload.path.root}`;
            const fileCType = fileUpload.headers['content-type'];
            // console.log(fileCType, 'fileCType');

            const fileName = fileUpload.filename;
            const { path } = generatePath(rootPath, fieldName);



            const fileExtension = fileUpload.filename.split('.').pop();

            // using a variable here because if this is an image, a thumbnail will be created with the same name as the original one
            const genRan = await UtilsService.genRan(8);
            const fullPath = await `${path}${genRan}-${fileName}`;
            const awsOp = {
                adapter: require('skipper-better-s3'),
                key: sails.config.aws.access_key,
                secret: sails.config.aws.secret_key,
                saveAs: fullPath,
                bucket: sails.config.aws.bucket,
                s3params: {
                    ACL: 'public-read'
                },
            };

            const config = {
                fieldName,
                awsOp,
                fileExtension,
                rootPath,
                fileName,
            }

            const procceed = await processUpload(config);
            console.log(procceed, 'procceed');
        }
    } catch (e) {
        console.log(e, 'inside UploadService');
        return false;
    }

}

我在哪个部分犯了导致这种行为的错误?我检查了我的路径,当我使用正确的文件名时,它也完全正确console.log

提前感谢您的任何建议和帮助。

4

1 回答 1

1

很久以前我花了很多时间来解决这个问题。尤其是您使用skipper-better-s3的文档并没有像 一样详细skipper,回过头来查看skipper文档实际上该saveAs字段不仅需要string,而且function您可以使用它来获取每个文件的文件名并根据需要返回它所以实际上你甚至根本不需要使用递归或 for 循环。

例如你的一些代码

const awsOp = {
    adapter: require('skipper-better-s3'),
    key: sails.config.aws.access_key,
    secret: sails.config.aws.secret_key,
    saveAs: (__newFileStream, next) => {
        // generatePath is what you wrote
        // __newFileStream.filename would the filename of each each before uploading
        // the path is pretty much the s3 key which includes your filename too
        const { path } = generatePath(rootPath, __newFileStream.filename, fieldName);
        return next(undefined, path);
    },
    bucket: sails.config.aws.bucket,
    s3params: {
        ACL: 'public-read'
    },
};

skipper文档https://www.npmjs.com/package/skipper#customizing-at-rest-filenames-for-uploads

于 2020-08-28T05:32:14.080 回答