背景
最近在开发一个功能时,涉及到向后端接口发送:
- JSON请求参数
- 多个文件
刚开始想通过RequestBody(application/json)形式进行传值,但是文件不好处理。有一个通过application/json传输文件数据的方法,就是将文件转成base64,然后在后端进行处理。但是这种方式涉及到大文件传输的时候,转成base64会消耗过多成本
于是找来找去找到按form表单的形式提交请求参数(按理来说本该如此),但是如何传输json数据倒变成了一个问题,直到找到这么一个文档,参考之后解决了目前的问题。
https://springdoc.cn/spring-file-upload-json/
解决历程
- 后端接口:
@PostMapping("/creation")
public void testFormData(@RequestPart("files") MultipartFile[] files,
@RequestPart("dto") Dto dto
) {
System.out.println("hello a shuge");
String jsonStr = JSONUtil.toJsonStr(dto);
System.out.println(jsonStr);
for (MultipartFile file : files) {
System.out.println(file.getOriginalFilename());
System.out.println(file.getName());
}
}
注意到,上面testFormData方法中的请求参数 使用的注解 是:@RequestPart
- 前端请求
function handleFileUpload(event) {
// 在这里构造上传要用的fileList
const files = event.target.files;
if (files) {
for (let i = 0; i < files.length; i++) {
if (fileList.length < 20 && files[i].type.includes('image')) {
fileList.push(URL.createObjectURL(files[i]));
}
}
}
}
let formData = new FormData();
let request = {}; // json数据
// fileList是上面方法中fileList.push(URL.createObjectURL(files[i]));添加的元素
for (let key in fileList) {
formData.append('files', new Blob(fileList), 'files'); // 往formData中添加blob数据,这里涉及到append另外一个用法
}
// 注意下面:设置json数据时候,第三个参数指定此时set的数据是application/json类型
formData.set('dto', new Blob([JSON.stringify(request)], { type: 'application/json' }));
// 遍历formData,打印到console
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
UploaderApi.publishProduct(formData)
.then((res) => {
if (res.success) {
console.log("success");
} else {
console.log("failed");
}
})
.catch((err) => {
console.log("error");
});
http.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
if (config.method === 'post') {
// 这里处理上传文件的请求
if (config.headers['Content-Type'] === 'multipart/form-data') {
const formData = new FormData();
// 构造新的formData(如果不需要添加reqId/stamp)那这步就可以省略了,直接config.data=formData就行
for (var pair of config.data.entries()) {
formData.append(pair[0], pair[1]);
}
formData.append('requestId', reqId);
formData.append('stamp', RequestUtil.generateTimestamp());
config.data = formData;
} else {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
config.data = {
...config.data,
requestId: reqId,
stamp: RequestUtil.generateTimestamp(),
};
}
}
return config;
},
(error) => {
// 对请求错误做些什么
return Promise.reject(error);
},
);
请求参数实例
以上,就可以通过axios请求后端接口传输 json字符串+多文件
注意
涉及到的内容
- SpringBoot中@RequestPart的用法
- 前端FomrData.append与set的区别
- 通过将requestBody以contentType=application/json形式写入formData中(里面其实是blob类型数据)