返回

Vue上传对象数组 Multipart 文件解决方案

vue.js

Vue:处理对象数组中的Multipart文件上传问题

在使用Vue构建前端应用时,经常会遇到需要向后端发送包含文件数据的请求。一种常见的情形是:需要发送一个对象数组,数组中的每个对象又包含一个Multipart文件数组。 这篇文章探讨针对此类情况的常见问题以及解决方案。

问题与原因分析

具体场景为,前端有一个数据结构,例如包含多个考试文件信息的数组,每个文件信息需要与一些其他属性一起提交。后端期望接收的格式是,一个 Vo 对象数组,Vo 对象中包含一个 MultipartFile 数组,用来存储上传的文件。

常见的错误做法是直接使用 JSON.stringifyFile 对象转换成字符串,再添加到 FormData 中。这样的做法导致后端无法正确解析上传的文件,因为它接收到的是文件的字符串表示,而不是二进制文件数据。

解决方案一:正确构造FormData

正确的做法是,直接将 File 对象添加到 FormData 中,不需要进行任何转换。前端代码需要根据后端接口的期望格式,正确构建 FormData 对象。

前端代码示例:

submitExamFile: function () {
    let formData = new FormData();

    this.files.forEach((fileInfo, index) => {
        fileInfo.file.forEach((file, fileIndex) => {  // 遍历 file 数组
          formData.append(`files[${index}].examFile[${fileIndex}]`, file); //注意这里
        });
        formData.append(`files[${index}].loginName`, "defaultLoginName"); //添加其他参数
    });

    return new Promise((resolve, reject) => {
        this.$api
            .post("/save", formData, {
                headers: {
                    'Content-Type': 'multipart/form-data' // 非常重要,手动设置Content-Type
                }
            })
            .then((response) => {
                resolve(Number(response.data));
            })
            .catch((err) => {
                reject(err);
            });
    });
},

关键点:

  1. 遍历文件数组: 首先需要遍历每个对象中的文件数组fileInfo.file
  2. FormData append: 使用 formData.append() 方法直接将 File 对象添加到 FormData 中。 后端可以方便接收MultipartFile 对象数组。
  3. Content-Type: 明确指定 Content-Typemultipart/form-data。虽然axios通常能自动检测并设置正确的Content-Type,但显式设置可以避免潜在问题。
  4. 参数命名: 后端 Controller 使用 @RequestParam("files ") List<Vo> files 注解接收参数。注意前后端变量名的匹配和空格问题,如果参数传递错误后端无法解析对象,会抛出BindingException 异常.需要结合自己后端定义的Controller 接口修改。

操作步骤:

  1. 在 Vue 组件中,获取到 File 对象。
  2. 创建一个 FormData 对象。
  3. 循环遍历对象数组以及每个对象包含的文件数组,并将文件和其它数据通过 formData.append() 添加到 FormData 对象中。
  4. 使用 axiosfetch 发送 FormData 对象到后端,并设置正确的 Content-Type

后端代码示例(保持不变):

@RequestMapping(value = "save", method = RequestMethod.POST, consumes = {"multipart/form-data"})
    public JsonResponse save(@RequestParam("files ") List<Vo> files ,
            HttpServletRequest request,
            HttpServletResponse response) {
        int rowEffected = service.save(files);
        return new JsonResponse().success(rowEffected);
    }

public class Vo {
    private String isRemoved;
    private MultipartFile[] examFile;

   //constructor, getter, setter...
}

解决方案二:优化文件上传大小限制

在处理包含大量或较大文件的上传时,可能会遇到上传失败的情况。这通常是因为服务器对上传文件的大小进行了限制。

常见错误: 服务器返回 413 Request Entity Too Large

解决方案: 需要检查并调整服务器端的最大上传文件大小限制。 例如在使用 Spring Boot 构建的后端应用中,可以在 application.propertiesapplication.yml 中配置以下属性:

spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB

max-file-size 配置单个文件的最大大小,而 max-request-size 配置整个请求的总大小。请根据实际需要调整这些值。

操作步骤:

  1. 定位后端项目的配置文件 (application.propertiesapplication.yml)。
  2. 添加或修改 spring.servlet.multipart.max-file-sizespring.servlet.multipart.max-request-size 属性,并设置为适当的值。
  3. 重启后端服务,使配置生效。

安全建议

  • 文件类型校验: 在前端和后端都要对上传的文件类型进行校验,避免上传恶意文件。
  • 文件大小限制: 严格限制上传文件的大小,防止恶意用户上传大文件导致服务器资源耗尽。
  • 存储安全: 确保上传的文件存储在安全的位置,并进行适当的权限控制,防止未经授权的访问。
  • 防御 CSRF 攻击: 使用 CSRF 令牌保护文件上传接口,防止跨站请求伪造攻击。可以采取在headers增加认证token的方法来预防,提高安全性。

处理包含 Multipart 文件的对象数组上传是一个常见但需要细致处理的问题。通过正确构建 FormData 对象、调整上传大小限制,并采取必要的安全措施,可以有效地解决这个问题,并确保文件上传的安全可靠。