最近有个需求,使用springboot做文件上传,并且可以控制限制的文件大小,文件类型等,于是配置几个属性
spring:
  servlet:
    # 文件上传大小限制
    multipart:
      # 单个文件大小 默认1M
      max-file-size: 20MB
      # 总请求大小 默认10M
      max-request-size: 100MB
      resolve-lazily: true

这样一来,当springmvc 发现用户上传的文件大小超过上述配置时就会抛出异常 org.springframework.web.multipart.MultipartException,于是使用全局捕获异常处理器,希望在这里返回用户一些自定义错误信息,但在这个处理器返回信息时,此时前端的请求状态码已经成了failed,前端接收不到任何相应;如下图:

springboot 返回相对文件路径给前端 springboot返回文件流_spring


全局处理器代码如下:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MultipartException.class)
    public ResultVo handleAll(MultipartException t) {
        
        System.err.println("Error: "+ t.getMessage());
        if (t.getCause() instanceof MaxUploadSizeExceededException) {
			// ...
        }
        ResultVo resultVo = new ResultVo();
        resultVo.setMessage("上传的文件过大,最大限制为 100MB");
        resultVo.setStatus(ResultVo.STATIC_FAILURE);
        return resultVo;
    }

后来,一波三折,终于在StackOverflow上找到问题,
https://stackoverflow.com/questions/23856254/how-to-nicely-handle-file-upload-maxuploadsizeexceededexception-with-spring-secu 这是由于tomcat的配置
server.tomcat.max-swallow-size 比上传的文件小,tomcat把请求直接取消了,于是加上配置
server.tomcat.max-swallow-size=1000MB 或者设置为-1 不限制
(这个配置在springboot2.2.5才有,具体哪个版本开始不知道。)
加上这个配置后,全局异常处理器终于能正常返回前端信息。但是又造成了另一个问题
只要用户上传了文件,无论多大(取决去server.tomcat.max-swallow-size配置),后端都会接收这个文件,保存在某个临时文件中,也就是说,文件大小超过max-file-size和max-request-size 配置了,抛出了MaxUploadSizeExceededException异常,并且在上面 GlobalExceptionHandler 捕获成功,当执行完上面handleAll方法后,还是无法立刻响应前端,而是等待文件的io流传输完成,再响应用户。

所以有没有前辈高人可以指点指点有没有别的办法可以实现这个需求:

无论用户上传多大的文件,后端能解析到文件的相关信息,但是此时文件字节流还没有传输,等待校验完文件信息,是否通过校验后,才决定要不要传输这个文件到服务器,这样就不会被无用的文件占用带宽,或者被恶意攻击;