我的 Web 应用程序 (react-node.js) 的用户应该能够将大型 zip 文件 (~20gb) 上传到 S3 存储桶。但在将文件上传到 S3 之前,我需要验证压缩文件并从 zip 中获取一些信息以将它们保存在数据库中。我使用
multer
和 busboy
进行上传,但我看到当用户上传文件时服务器内存迅速减少。对于像 50-400mb 这样的小文件,它可以工作。但是在上传完成之前,每次请求都会中断重文件。在浏览器的网络面板上,我看到 ERR:CONNECTION_RESET 错误。
在这种情况下上传大文件的正确方法是什么?
尝试使用 multer 和 busboy 包,但它们都使用服务器内存并导致问题。
Busboy 配置:
public busboyInterceptor(req: Request): Promise<IFileMetadata> {
return new Promise((resolve, reject) => {
let metadata = {
fieldname: '',
encoding: '',
mimetype: '',
originalname: '',
path: '',
destination: '',
filename: '',
size: 0,
};
const busboy = Busboy({ headers: req.headers });
busboy.on('file', (name, file, info) => {
const destFolder = path.join(
global.__basedir,
this.configService.get<string>('FILE_UPLOAD_FOLDER'),
);
const fileName = `${uuid()}.zip`;
const filePath = `${destFolder}/${fileName}`;
metadata.fieldname = name;
metadata.encoding = info.encoding;
metadata.mimetype = info.mimeType;
metadata.originalname = info.filename;
metadata.destination = destFolder;
metadata.path = filePath;
metadata.filename = fileName;
if (!ArchiveMimetypes.includes(info.mimeType)) {
throw new BadRequestException('Accepted mime type is zip ');
}
file.on('data', (data) => {
metadata.size += data.length;
});
file
.pipe(fs.createWriteStream(filePath, { flags: 'a' }))
.on('error', (e) => {
console.error('Failed write file', e);
throw new HttpException(
'Internal server error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
});
});
busboy.on('error', (e) => {
console.error('Failed upload file', e);
throw new HttpException(
'Internal server error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
});
busboy.on('finish', () => {
console.log(metadata);
console.log('File uploaded');
resolve(metadata);
});
req.pipe(busboy);
});
多重配置:
createMulterOptions(): MulterModuleOptions {
const destinationPath = path.join(
global.__basedir,
this.configService.get<string>('FILE_UPLOAD_FOLDER'),
);
return {
fileFilter(req, file, callback) {
if (ArchiveMimetypes.includes(file.mimetype)) {
callback(null, true);
} else {
callback(
new BadRequestException('Accepted mime type is zip '),
false,
);
}
},
storage: diskStorage({
destination: destinationPath,
filename: function (req, file, callback) {
const uniqueSuffix = uuid();
callback(null, uniqueSuffix + `.zip`);
},
}),
limits: {
fileSize: FileSizes.GB,
},
};
}