使用multer-s3无法上传大于1MB文件的问题及提速咨询
问题解决:multer-s3 大文件上传失败及提速方案
问题原由
你遇到的大文件(>1MB)上传时指定代码块不执行、无报错却返回201的问题,核心原因是原代码中异步处理的顺序错误:
在控制器里手动调用s3upload.single('file')后,没有等待multer的异步上传流程完成,就直接执行了res.status(201).send("Success")。小文件因为处理速度快,能在响应发送前完成上传;但大文件处理耗时更长,响应已经提前发送,导致multer的回调函数根本没机会执行。
原代码问题点
import { Request, Response } from 'express'; import { v4 as uuidv4 } from 'uuid'; import multer from 'multer'; import multerS3 from "multer-s3" import s3 from "../config/amazons3" const uploadController = { transferFile: async (req, res) => { try { const s3upload = multer({ storage: multerS3({ s3: s3, acl: 'public-read', bucket: 'filetransferawsbucket1', metadata: (req, file, cb) => { cb(null, {fieldName: file.fieldname}) }, key: (req, file, cb) => { try { console.log("File", file) const key: string = `medium_zip_file_${uuidv4()}` cb(null, key) } catch (error) { cb(error) } } }), limits: { fileSize: 5 * 1024 * 1024 * 1024, fieldSize: 52428800 }, fileFilter: (req, file, cb) => { if (file.mimetype === 'application/zip') { cb(null, true) } else { cb(new Error('Invalid file type. Only zip files are allowed.')) } }, }) console.log('Before Multer Middleware') // 大文件上传时,这个异步回调还没执行,响应就已经发送了 s3upload.single('file')(req, res, (err) => { console.log('After Multer Middleware') if (err) { console.log('Multer error:', err) return res.status(500).json({ error: "Error processing file upload" }) } }) // 直接返回响应,打断了multer的异步上传流程 res.status(201).send("Success") } catch (error) { console.log("TRANSFER FILE ERROR", error) res.status(500).json({ error: "Error transferring file" }) } } }
未执行的代码块:
s3upload.single('file')(req, res, (err) => { console.log('After Multer Middleware') if (err) { console.log('Multer error:', err) return res.status(500).json({ error: "Error processing file upload" }) } })
已验证的解决方法:调整中间件位置
把multer-s3的中间件直接挂载到路由上,让Express的中间件流程自动处理异步顺序,确保文件上传完成后再进入控制器逻辑。
修改后的代码
uploadRouter.ts
import express from "express" import uploadController, { s3upload } from "../controllers/uploadContoller" const router = express.Router() // 将s3upload中间件放在路由定义中,由Express管理执行顺序 router.post("/transferFile", s3upload.single("file"), uploadController.transferFile) export default router
uploadController.ts
import { Request, Response } from 'express'; import { TransferModel } from "../models/transferModel"; import { v4 as uuidv4 } from 'uuid'; import multer from 'multer'; import multerS3 from "multer-s3" import s3 from "../config/amazons3" interface IUploadContoller { transferFile: (req: Request, res: Response) => Promise<void> transferFileBusBoy?: (req: Request, res: Response) => Promise<void> } // 抽离multer配置,作为全局可复用的中间件 export const s3upload = multer({ storage: multerS3({ s3: s3, acl: 'public-read', bucket: 'filetransferawsbucket1', metadata: (req, file, cb) => { cb(null, {fieldName: file.fieldname}) }, key: (req, file, cb) => { try { console.log("***FILE***", file) const key: string = `medium_zip_file_${uuidv4()}` cb(null, key) } catch (error) { cb(error) } } }), limits: { fileSize: 5 * 1024 * 1024 * 1024, fieldSize: 5 * 1024 * 1024 * 1024, }, fileFilter: (req, file, cb) => { if (file.mimetype === 'application/zip') { cb(null, true) } else { cb(new Error('Invalid file type. Only zip files are allowed.')) } }, }) const uploadController: IUploadContoller = { transferFile: async (req: Request, res: Response) => { try { console.log('Before Multer Middleware') res.status(201).send("Success") } catch (error) { console.log("TRANSFER FILE ERROR", error) res.status(500).json({ error: "Error transferring file" }) } }, } export default uploadController
大文件上传提速建议
目前你已经能上传1GB文件但耗时5分钟,可以试试这些优化方向:
启用S3分片上传
在AWS SDK配置中开启分片上传,让大文件自动拆分后并行传输:// 在../config/amazons3中修改S3客户端配置 import { S3Client } from "@aws-sdk/client-s3"; const s3 = new S3Client({ region: "你的存储桶区域", multipartUploadThreshold: 5 * 1024 * 1024, // 大于5MB自动分片 multipartUploadSize: 5 * 1024 * 1024, // 每个分片大小 maxAttempts: 3, // 分片上传失败重试次数 });对齐服务器与S3区域
确保你的Node.js服务器和S3存储桶在同一AWS区域,跨区域传输会大幅增加延迟和耗时。前端分片上传
在前端把大文件分成10MB-50MB的小分片,并行上传到S3后再合并,既能利用多线程提升速度,还支持断点续传。优化AWS SDK超时设置
增大超时时间避免大文件上传中途断开:const s3 = new S3Client({ region: "你的存储桶区域", requestTimeout: 300000, // 5分钟请求超时 connectionTimeout: 60000, // 1分钟连接超时 });文件压缩预处理
对zip文件在前端用更高压缩率的算法二次压缩,减小文件体积后再上传,从根源减少传输时间。
内容的提问来源于stack exchange,提问作者firefly1095
相关产品推荐
相关产品推荐

