Node.js Express多图上传遇ERR_HTTP_HEADERS_SENT错误求助
解决Express多图上传中的ERR_HTTP_HEADERS_SENT错误
ERR_HTTP_HEADERS_SENT错误的核心原因是多次向客户端发送HTTP响应,你的代码存在两个关键问题:
file[i].mv是异步回调函数,循环会直接执行完毕并返回200响应,但后续回调中如果出现错误,又会尝试发送500响应,导致重复发送响应头。- 同步检查(文件类型、大小)的
return语句虽然会退出函数,但如果之前已经触发了mv的异步操作,回调里的res仍然会执行,造成重复响应。
修复后的代码
import path from 'path'; export const addImages = async(req, res) => { if(req.files === null) return res.status(400).json({msg: "No File Uploaded"}); const productId = req.params.id; const userId = req.userId; const files = req.files.prodImages; const allowedType = ['.png','.jpg','.jpeg']; // 封装单个文件的处理逻辑,返回Promise const processFile = async (file) => { const fileSize = file.data.length; const ext = path.extname(file.name).toLowerCase(); const fileName = file.md5 + ext; // 同步校验,抛出错误而非直接返回响应 if(!allowedType.includes(ext)) throw new Error("Invalid Images"); if(fileSize > 5000000) throw new Error("Image must be less than 5 MB"); // 将mv回调转换为Promise,便于await处理 await new Promise((resolve, reject) => { file.mv(`./public/images/${fileName}`, (err) => { err ? reject(err) : resolve(); }); }); // 保存图片信息到数据库 await Image.create({ name: fileName, productId: productId, userId: userId }); }; try { // 兼容单文件上传(req.files.prodImages可能不是数组) const filesArray = Array.isArray(files) ? files : [files]; // 并行处理所有文件,等待全部完成 await Promise.all(filesArray.map(processFile)); res.status(200).json({msg: "Images Added"}); } catch (error) { // 统一处理所有错误,仅发送一次响应 let statusCode = 400; if(error.message === "Invalid Images" || error.message === "Image must be less than 5 MB") { statusCode = 422; } else if(error.message.includes("mv")) { statusCode = 500; } res.status(statusCode).json({msg: error.message}); } };
关键改进点
- 异步操作Promise化:将
file.mv的回调逻辑转换为Promise,用await控制异步流程,避免回调嵌套导致的响应混乱。 - 统一错误捕获:所有校验和操作错误都在顶层
try/catch中处理,确保只会向客户端发送一次HTTP响应。 - 批量异步处理:用
Promise.all并行处理所有文件,确保所有上传和数据库操作完成后才返回成功响应。 - 兼容单图上传:处理
req.files.prodImages为单个文件的情况,避免数组遍历报错。
内容的提问来源于stack exchange,提问作者DENIS MBUTHIA
相关产品推荐
相关产品推荐

