升级Spring Boot 3后调用ServletResponse.getOutputStream()报错求助
升级Spring Boot 3后获取ServletOutputStream异常的解决方案
问题背景
将项目升级到Spring Boot 3后,调用HttpServletResponse.getOutputStream()时抛出异常,该问题在Spring Boot 2.x版本中从未出现。
异常信息
{ "type": "about:blank", "title": "Bad Request", "status": 400, "detail": "Invoked method public abstract jakarta.servlet.ServletOutputStream jakarta.servlet.ServletResponse.getOutputStream() throws java.io.IOException is no accessor method", "instance": "/download/reports.mp4" }
相关控制器代码:
import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.infraview.uss.videoeventapi.entrypoints.UseCaseFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping(path = "/download") @RequiredArgsConstructor @Slf4j public class DownloadController{ private final UseCaseFactory useCaseFactory; @GetMapping(path = "/{fileName}") public void download(@PathVariable String fileName, @RequestParam String ip, HttpServletResponse response) throws IOException { var output = response.getOutputStream(); useCaseFactory.makeDownloadVideo(ip, fileName, output) .execute(); } }
已尝试升级至Spring Boot 3.1.0和Spring Cloud 2022.0.2,问题仍未解决。
解决方案
1. 移除不必要的@EnableWebMvc注解
Spring Boot 3中,若自定义配置类添加了@EnableWebMvc,会覆盖默认Web MVC配置,触发参数绑定的严格检测——Spring会将HttpServletResponse视为普通Bean,错误地把getOutputStream()当作属性访问器处理。
如果没有特殊的Web MVC自定义需求,直接删除配置类上的@EnableWebMvc即可。
2. 改用StreamingResponseBody处理流式输出
替换原有的void返回方式,使用Spring提供的StreamingResponseBody实现流式下载,避免直接操作HttpServletResponse:
import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.infraview.uss.videoeventapi.entrypoints.UseCaseFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; @RestController @RequestMapping(path = "/download") @RequiredArgsConstructor @Slf4j public class DownloadController{ private final UseCaseFactory useCaseFactory; @GetMapping(path = "/{fileName}") public ResponseEntity<StreamingResponseBody> download(@PathVariable String fileName, @RequestParam String ip) { StreamingResponseBody body = outputStream -> { useCaseFactory.makeDownloadVideo(ip, fileName, outputStream).execute(); }; return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"") .body(body); } }
3. 排查自定义参数解析器/拦截器
若项目中有自定义的ArgumentResolver或HandlerInterceptor,检查是否错误地对HttpServletResponse这类Servlet原生对象执行了属性绑定或额外处理。调整组件逻辑,不对这类对象进行参数绑定操作。
内容的提问来源于stack exchange,提问作者drdr
相关产品推荐
相关产品推荐

