前端使用axios或fetch上传文件,服务端报错:the request was rejected because no multipart boundary was found
当前端使用表单上传文件,但是使用Axios或Fetch发送请求时,如果使用不当,会报错:Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found 前端代码如下:
前后端代码及报错信息
<input type="file" class="hidden-upload-input" @change="uploadCoverHandle" name="file" accept="image/*" enctype="multipart/form-data"/>
const uploadCoverHandle = (e:Event)=>{
var formData = new FormData();
//@ts-ignore
formData.append( 'file',e.target.files[0])
console.log(e)
//useUploadClient("/common/qiniu/uploadFileByServe",formData)
fetch(url, {
url,
body:formData,
method:'POST',
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
后端代码如下:
@PostMapping("/uploadFileByServe")
public R<QiniuPutRet> uploadFileByServe(@RequestParam("file")
MultipartFile file) throws IOException {
log.info("--------------uploadFile-" + file.toString());
log.info(file.getOriginalFilename() + "=" + file.getName() + "=" + file.getSize());
InputStream inputStream = file.getInputStream();
Response res = uploadManager.put(inputStream, null, getUploadToken(),null,null);
// 解析上传成功的结果
QiniuPutRet qiniuPutRet = res.jsonToObject(QiniuPutRet.class);
log.info(qiniuPutRet.toString());
qiniuPutRet.setDomain(qiniuConfig.getDomain());
return R.success(qiniuPutRet);
}
会发现后端报上述错误。
原因探究
因为,当我们使用HTTP form表单进行文件上传时,请求数据实际上根据参数分片封装的,大致的数据格式如下:
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file" accept="image/*" />
<button type="submit">Submit</button>
</form>
//数据格式
------WebKitFormBoundaryKrjTL2X3JXEobJYG
Content-Disposition: form-data; name="file"; filename="wx_souyisou.png"
Content-Type: image/png
// 请求头
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarycAmE6ANaU471at2V
可以看到,在"multipart/form-data"后面附带了一个boundary属性。 这个boundary的值就是请求数据中的分隔符,服务器就是根据这个分隔符,将数据拆分为多个参数,然后分别解析其数据的。
如果需要自己构造这个boundary属性,可以参考:
https://developer.mozilla.org/zh-CN/docs/Learn/Forms/Sending_forms_through_JavaScript
当使用form表单进行文件上传时,浏览器会自动为我们附加这个boundary属性。
即数据格式类似如下:
POST /test.html HTTP/1.1
Host: example.org
Content-Type: multipart/form-data;boundary="boundary"
--boundary
Content-Disposition: form-data; name="field1"
value1
--boundary
Content-Disposition: form-data; name="field2"; filename="example.txt"
value2
但是,当我们使用ajax上传时(如axios,fetch),如果没有自己构造boundary属性,默认的请求数据如下:
//请求头
Content-Type: multipart/form-data
// 请求负载
------WebKitFormBoundaryKrjTL2X3JXEobJYG
Content-Disposition: form-data; name="file"; filename="wx_souyisou.png"
Content-Type: image/png
------WebKitFormBoundaryKrjTL2X3JXEobJYG--
发现,并没有boundary属性, 上述数据是以Payload负载的形式传送的。
解决方案
⚡ 其实解决办法也很简单,请求头中不要设置'Content-Type': 'multipart/form-data'
即可.
代码修改如下:
fetch(url, {
url,
body:formData,
method:'POST',
headers: {
// 不要设置 'Content-Type': 'multipart/form-data', 或设置为 false
//'Content-Type': 'multipart/form-data'
}
})
因为一旦我们设置了该属性,浏览器和fetch将不会再为我们自动附加这个boundary。