使用Javascript Fetch API发送文件至Express后端时fs.writeFile保存报错
问题成因
- 客户端请求头配置错误:使用
FormData作为请求体发起文件上传时,手动将Content-Type设置为application/x-www-form-urlencoded。正常流程下,浏览器遇到FormData格式的请求体,会自动生成带上传内容分隔边界(boundary)的multipart/form-data请求头,手动覆盖请求头会导致服务端无法识别请求的真实格式,自然拆分不出正确的二进制文件流,最终拿到的文件字段是结构不合法的普通对象/字符串,直接触发fs.writeFile的入参类型校验报错。 - 服务端缺少对应格式的请求解析能力:当前服务端仅适配了urlencoded文本类型的请求解析,完全不具备处理multipart文件流的能力,即便客户端修正了请求头,没有专用的解析组件,也无法从原始请求流中提取出符合写入要求的Buffer格式文件内容。
解决方案
客户端代码修正
- 移除
fetch配置中手动设置的Content-Type请求头,将该头的生成逻辑完全交由浏览器自动处理。修正后的上传代码如下:
const upload = _ => { let form = new FormData(); form.append("file", document.getElementById("my-file-selector").files[0]) fetch('http://localhost:3377/me/uploadPfp', { method: 'POST', headers: { "Authorization": "<%= locals.user.token %>" }, body: form, }).then( response => response.json() ).then( success => console.log(success) ).catch( error => console.log(error) ); };
服务端逻辑修正
- 替换文件上传的解析逻辑:不要使用
body-parser类组件处理文件上传,这类组件仅支持解析json、urlencoded格式的文本请求,完全不支持multipart格式的二进制文件流。引入multer这类专用的multipart解析中间件,配置好单文件接收规则后,中间件会自动把上传文件的二进制Buffer内容挂载到req.file.buffer字段上,该字段是可以直接传给fs.writeFile的合法入参。 - 调用
fs.writeFile时,直接将解析得到的req.file.buffer作为data参数传入即可,不要把未解析的请求对象、原始表单字段直接作为写入内容传入。
高频踩坑提醒:FormData格式的上传请求,绝对不能手动指定
Content-Type,这类请求的请求头必须由浏览器根据实际上传内容自动生成,手动设置100%会导致服务端解析失败。
内容的提问来源于stack exchange,提问作者Ulises Viña
相关产品推荐
相关产品推荐

