这个错误通常表明您尝试从Spring MVC
返回一个已使用的HttpServletResponse
对象。
原因:这可能是由于直接调用HttpServletResponse
的getWriter()
或getOutputStream()
方法,或者由于在控制器方法中抛出异常而自动调用HttpServletResponse
的write()
方法。
修改建议:您可以确保在控制器方法中没有调用任何HttpServletResponse
的方法,并且不要在控制器方法中抛出异常。 文章来源:https://www.toymoban.com/news/detail-794860.html
规避建议:如果需要向客户端返回响应,请使用返回相应的对象,例如String
、 ModelAndView
或RedirectView
。 此外,您还可以使用@ResponseStatus
和@ExceptionHandler
注解来处理异常情况,并生成适当的响应。文章来源地址https://www.toymoban.com/news/detail-794860.html
问题重现
ResponsePostInterceptor 里注入response.getWriter().write
package com.zhangziwa.practisesvr.interceptor;
import com.zhangziwa.practisesvr.utils.response.ResponseContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component
public class ResponsePostInterceptor implements HandlerInterceptor {
# 调用 response.getWriter().write
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.err.println("***ResponsePostInterceptor.preHandle***");
response.setHeader("test-test", "test-test");
response.getWriter().write("Response content");
response.flushBuffer();
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.err.println("***ResponsePostInterceptor.postHandle***");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.err.println("***ResponsePostInterceptor.afterCompletion***");
ResponseContext.clear();
}
}
Controller 正常返回 ResponseEntity
@RequestMapping(value = "/getAllStudents4", method = RequestMethod.GET)
public ResponseEntity<List<Student>> getAllStudents4() {
System.err.println("***Controller.getAllStudents4***");
List<Student> students = userService.listStudents3(1, 5);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("test", "test");
return ResponseEntity.ok().headers(httpHeaders).contentType(MediaType.APPLICATION_JSON).body(students);
}
ResponseBodyAdvice 对 ResponseEntity进行增强
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import static java.util.Objects.nonNull;
@ControllerAdvice
public class ResponsePostAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
System.err.println("***ResponsePostAdvice.supports***");
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class clazz, ServerHttpRequest request, ServerHttpResponse response) {
System.err.println("***ResponsePostAdvice.beforeBodyWrite***");
HttpHeaders headers = response.getHeaders();
// 分页信息添加到ServerHttpResponse
HttpHeaders headersContext = ResponseContext.getHeaders();
if (nonNull(headersContext) && !headersContext.isEmpty()) {
headersContext.forEach((key, values) -> values.forEach((value) -> {
headers.addIfAbsent(key, value);
}));
}
// 状态码添加到ServerHttpResponse
if (nonNull(ResponseContext.getResponseCode())) {
response.setStatusCode(ResponseContext.getResponseCode());
}
# 这里会报错
return body;
}
}
异常拦截GlobalExceptionHandler
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<String> handleException(Exception ex) {
System.err.println("***GlobalExceptionHandler.handleException:" + ex.getMessage() + "***");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred");
}
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<String> handleNotFoundException(NotFoundException ex) {
System.err.println("***GlobalExceptionHandler.handleNotFoundException***");
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
}
}
调用路径分析
# 拦截器的preHandle (这里注入了response.getWriter().write)
***ResponsePostInterceptor.preHandle***
# Controller层
***Controller.getAllStudents4***
# ResponsePostAdvice进行增强后返回ServerHttpResponse
***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***
## 这里报IllegalStateException了 被 @ControllerAdvice修饰的GlobalExceptionHandler 拦截到
***GlobalExceptionHandler.handleException:getWriter() has already been called for this response***
# 异常返回ResponseEntity 又被ResponsePostAdvice捕捉然后进行增强
***ResponsePostAdvice.supports***
***ResponsePostAdvice.beforeBodyWrite***
# 又报IllegalStateException,但是此时没被GlobalExceptionHandler 拦截
java.lang.IllegalStateException: getWriter() has already been called for this response
# 吃啥程序蹦了,故ResponsePostInterceptor.postHandle未执行。但是afterCompletion是否异常都会执行,所以执行了
***ResponsePostInterceptor.afterCompletion***
# 这里又执行一遍拦截器,但是未进入Controller层,不是很懂
***ResponsePostInterceptor.preHandle***
***ResponsePostInterceptor.postHandle***
***ResponsePostInterceptor.afterCompletion***
到了这里,关于SpringBoot 调用错:getWriter() has already been called for this response的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!