因此,我需要更改 Google Cloud Storage 的此功能,以便它可以上传多个文件而不是一个。我正在尝试找到一个好的解决方案,使其始终等待所有文件上传。不知道如何使其异步 - 我应该在
stream.on('finish',(...))
上等待还是在 file.makePublic().then(...)
上等待,这绝对是一个 Promiste,我可以用 Promise.all()
收集然后解决 next()
。
或者如果谷歌已经有一个没有在他们的文档中披露的解决方案,那就更好了。
功能:
function sendUploadsToGCS (req, res, next) {
if (!req.files) {
return next()
}
let vals = Object.values(req.files)
for(let f of vals){
const gcsname = Date.now() + f[0].originalname
const file = bucket.file(gcsname)
const stream = file.createWriteStream({
metadata: {
contentType: f[0].mimetype
},
resumable: false
})
stream.on('error', (err) => {
f[0].cloudStorageError = err
next(err)
})
stream.on('finish', () => {
f[0].cloudStorageObject = gcsname;
file.makePublic().then(() => {
f[0].cloudStoragePublicUrl = getPublicUrl(gcsname)
console.log('pub url: ', getPublicUrl(gcsname))
next()
})
})
stream.end(f[0].buffer)
}
}
原始函数(针对一个文件):https://cloud.google.com/nodejs/getting-started/using-cloud-storage#upload_to_cloud_storage
我是这样解决的:
function sendUploadsToGCS (req, res, next) {
if (!req.files) {
return next()
}
let promises = []
let vals = Object.values(req.files)
for(let f of vals){
const gcsname = Date.now() + f[0].originalname
const file = bucket.file(gcsname)
const stream = file.createWriteStream({
metadata: {
contentType: f[0].mimetype
},
resumable: false
})
stream.on('error', (err) => {
f[0].cloudStorageError = err
next(err)
})
stream.end(f[0].buffer)
promises.push(
new Promise ((resolve, reject) => {
stream.on('finish', () => {
f[0].cloudStorageObject = gcsname;
file.makePublic().then(() => {
f[0].cloudStoragePublicUrl = getPublicUrl(gcsname)
resolve()
})
})
})
)
}
Promise.all(promises).then(() => next())
}
我在处理大量小文件时也遇到了类似的问题。为了控制上传,我决定使用 p-limit 库,它处理并发请求限制,并且我仅在代码中的这一位置上传所有文件。
这种方法让我获得了与此类似的结果:
Number of files to upload: 186
All files uploaded to GCS: 207.94119999930263 ms
这是我为其他处理此问题的人提供的代码:
const downloadSatelliteFiles = async (files: FileData[]) => {
const limit = pLimit(5);
const promises: Promise<void>[] = [];
files.forEach((file) => {
promises.push(
limit(() => {
uploadFileToGCS(file.fileName, file.buffer, file.contentType);
})
);
});
await Promise.all(promises);
return;
};
const uploadFileToGCS = (filename: string, data: any, contentType: string) => {
return new Promise(async (resolve, reject) => {
const file = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET).file(filename);
const stream = file.createWriteStream({
metadata: {
contentType,
cacheControl: "no-cache",
},
resumable: false,
});
stream.on("error", (err) => {
console.log("UPLOAD_ERROR");
console.log(err);
});
stream.on("finish", () => {
resolve("ok");
});
stream.end(data);
});
};