You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 2.7.5中Multipart上传超限时自定义响应的实现问题

解决Spring Boot 2.7.5 Multipart文件上传超出大小返回自定义响应的问题

问题根源

你遇到的核心问题是:Multipart请求的大小校验是在Servlet容器层面完成的(从错误码SRVE8021E判断,你使用的是WebSphere容器),这个校验发生在Spring的DispatcherServlet处理请求之前,因此Spring的@ControllerAdvice无法捕获容器抛出的异常,导致你的自定义处理逻辑执行后被容器默认错误响应覆盖。

可行解决方案

方案一:配置WebSphere容器的自定义错误处理

针对WebSphere容器,通过Spring Boot的容器配置类绑定错误映射,将容器抛出的超大文件异常导向自定义端点:

  1. 配置WebSphere容器错误映射:
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory
import org.springframework.boot.web.embedded.websphere.WebSphereServletWebServerFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class WebServerConfig {
    @Bean
    fun webServerFactory(): ConfigurableServletWebServerFactory {
        val factory = WebSphereServletWebServerFactory()
        // 将容器抛出的IllegalStateException(对应超大文件错误)映射到自定义端点
        factory.addErrorPages(org.springframework.boot.web.servlet.error.ErrorPage(
            IllegalStateException::class.java, "/api/errors/file-too-large"
        ))
        return factory
    }
}
  1. 编写自定义错误端点返回响应:
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class CustomErrorController(
    private val multipartProperties: org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
) {
    @GetMapping("/api/errors/file-too-large")
    fun handleFileTooLarge(): ResponseEntity<CustomErrorDto> {
        val fileSizeMegabyte = multipartProperties.maxFileSize.toMegabytes().toString()
        val message = "文件过大,上传文件不能超过${fileSizeMegabyte}MB"
        return ResponseEntity(
            CustomErrorDto("FILE_TOO_LARGE", message, mapOf("maxFileSize" to fileSizeMegabyte)),
            HttpStatus.BAD_REQUEST
        )
    }
}

方案二:自定义MultipartResolver主动校验大小

绕过容器提前校验,在Spring层面实现文件大小检查,让@ControllerAdvice能捕获异常:

  1. 自定义MultipartResolver:
import org.springframework.web.multipart.MaxUploadSizeExceededException
import org.springframework.web.multipart.MultipartException
import org.springframework.web.multipart.MultipartHttpServletRequest
import org.springframework.web.multipart.commons.CommonsMultipartResolver
import javax.servlet.http.HttpServletRequest

class CustomMultipartResolver(
    private val maxFileSize: Long
) : CommonsMultipartResolver() {
    override fun resolveMultipart(request: HttpServletRequest): MultipartHttpServletRequest {
        try {
            val multipartRequest = super.resolveMultipart(request)
            // 遍历所有文件检查大小
            multipartRequest.fileMap.values.forEach { file ->
                if (file.size > maxFileSize) {
                    throw MaxUploadSizeExceededException(maxFileSize)
                }
            }
            return multipartRequest
        } catch (e: Exception) {
            if (e is MultipartException) {
                throw e
            }
            throw MultipartException("文件解析失败", e)
        }
    }
}
  1. 将自定义Resolver注入Spring容器:
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.web.multipart.MultipartResolver

@Configuration
class MultipartConfig(
    private val multipartProperties: MultipartProperties
) {
    @Bean(name = ["multipartResolver"])
    fun multipartResolver(): MultipartResolver {
        return CustomMultipartResolver(multipartProperties.maxFileSize.toBytes())
    }
}
  1. 开启延迟解析(保持你之前配置的spring.servlet.multipart.resolve-lazily: true),让文件解析延迟到Controller处理阶段,确保Spring异常处理器能捕获异常。

方案三:使用Filter提前拦截请求大小

在容器解析Multipart之前,通过Filter检查请求Content-Length,超过阈值直接返回自定义响应:

import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.stereotype.Component
import javax.servlet.*
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

@Component
class MultipartSizeCheckFilter(
    private val multipartProperties: org.springframework.boot.autoconfigure.web.servlet.MultipartProperties
) : Filter {
    override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
        val httpRequest = request as HttpServletRequest
        val contentType = httpRequest.contentType
        // 仅处理Multipart类型请求
        if (contentType?.startsWith("multipart/form-data") == true) {
            val contentLength = httpRequest.contentLengthLong
            val maxSize = multipartProperties.maxRequestSize.toBytes()
            if (contentLength > maxSize) {
                val httpResponse = response as HttpServletResponse
                val fileSizeMegabyte = multipartProperties.maxFileSize.toMegabytes().toString()
                val errorMessage = """{"code":"FILE_TOO_LARGE","message":"文件过大,上传文件不能超过${fileSizeMegabyte}MB","maxFileSize":"${fileSizeMegabyte}"}"""
                
                httpResponse.status = HttpStatus.BAD_REQUEST.value()
                httpResponse.contentType = MediaType.APPLICATION_JSON_VALUE
                httpResponse.writer.write(errorMessage)
                return
            }
        }
        chain.doFilter(request, response)
    }
}

注意:该方案依赖客户端准确发送Content-Length请求头,若客户端未发送或值不准确,校验会失效。


内容的提问来源于stack exchange,提问作者MrMyth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 05:55:15