FormData传输JSON同时上传单个/多个文件问题

背景

最近在开发一个功能时,涉及到向后端接口发送:

  • JSON请求参数
  • 多个文件
    刚开始想通过RequestBody(application/json)形式进行传值,但是文件不好处理。有一个通过application/json传输文件数据的方法,就是将文件转成base64,然后在后端进行处理。但是这种方式涉及到大文件传输的时候,转成base64会消耗过多成本

于是找来找去找到按form表单的形式提交请求参数(按理来说本该如此),但是如何传输json数据倒变成了一个问题,直到找到这么一个文档,参考之后解决了目前的问题。
https://springdoc.cn/spring-file-upload-json/

解决历程

  1. 后端接口:
    @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

  1. 前端请求
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类型数据)
posted @ 2024-04-24 09:55  你啊347  阅读(207)  评论(0编辑  收藏  举报