使用FormData时Axios无法设置Content-Type头的问题咨询
当发送包含FormData的axios请求时:
axios({ url: "/public-resolutions/decision-files/", method: "post", processData: false, data: formData, headers: { "Content-Type": "multipart/form-data; charset=UTF-8", }, });
在请求拦截器中执行console.log(config),无法看到手动设置的Content-Type头;但将data替换为空对象后,头信息能正常显示。
补充背景:服务器接收的文件名默认采用latin1编码,部分场景下导致异常,希望强制使用UTF-8编码,使用的axios版本为0.27.2,FormData构造代码如下:
const formData = new FormData(); formData.append("excel", excel); for (let i = 0; i < pdfs.length; i++) { formData.append("pdfs", pdfs[i]); }
axios 0.27.2对FormData类型的请求数据有特殊处理逻辑:当检测到data为FormData实例时,会主动删除手动设置的Content-Type头,转而交由浏览器自动生成包含正确boundary分隔符的multipart/form-data头。这个删除操作发生在请求拦截器执行之后,因此在拦截器中打印config时,手动设置的Content-Type已经被移除,自然无法看到。
而当data为空对象时,axios不会触发这个自动处理逻辑,手动设置的Content-Type会被保留,因此拦截器中能正常看到。
针对你需要让文件名以UTF-8编码传输的需求,无需手动设置Content-Type的charset(multipart/form-data的charset参数不控制文件名编码),正确的做法是在向FormData追加文件时,按照RFC 5987标准指定UTF-8编码的文件名:
const formData = new FormData(); // 对excel文件指定UTF-8编码的文件名 formData.append("excel", excel, `filename*=UTF-8''${encodeURIComponent(excel.name)}`); // 对pdf文件同理 for (let i = 0; i < pdfs.length; i++) { formData.append("pdfs", pdfs[i], `filename*=UTF-8''${encodeURIComponent(pdfs[i].name)}`); }
这样设置后,服务器会识别到filename*参数中的UTF-8编码文件名,避免因编码问题导致的异常,同时保留axios自动生成带boundary的Content-Type头,确保请求格式正确。
如果确实需要强制设置自定义Content-Type头(不推荐,易破坏请求格式),可以通过transformRequest绕过自动删除逻辑,但需手动匹配正确的boundary:
axios({ url: "/public-resolutions/decision-files/", method: "post", processData: false, data: formData, transformRequest: [(data, headers) => { headers["Content-Type"] = "multipart/form-data; charset=UTF-8; boundary=----CustomBoundary"; return data; }], });
内容的提问来源于stack exchange,提问作者anon

