getWriter() has already been called for this response

2024-01-13 12:44

本文主要是介绍getWriter() has already been called for this response,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这个错误通常表明您尝试从Spring MVC返回一个已使用的HttpServletResponse对象。

原因:这可能是由于直接调用HttpServletResponsegetWriter()getOutputStream()方法,或者由于在控制器方法中抛出异常而自动调用HttpServletResponsewrite()方法。

修改建议:您可以确保在控制器方法中没有调用任何HttpServletResponse的方法,并且不要在控制器方法中抛出异常。

规避建议:如果需要向客户端返回响应,请使用返回相应的对象,例如StringModelAndViewRedirectView。 此外,您还可以使用@ResponseStatus@ExceptionHandler注解来处理异常情况,并生成适当的响应。

问题重现

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@Overridepublic 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;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.err.println("***ResponsePostInterceptor.postHandle***");}@Overridepublic 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);}

ResponseBodyAdviceResponseEntity进行增强

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 {@Overridepublic boolean supports(MethodParameter returnType, Class converterType) {System.err.println("***ResponsePostAdvice.supports***");return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class clazz, ServerHttpRequest request, ServerHttpResponse response) {System.err.println("***ResponsePostAdvice.beforeBodyWrite***");HttpHeaders headers = response.getHeaders();// 分页信息添加到ServerHttpResponseHttpHeaders headersContext = ResponseContext.getHeaders();if (nonNull(headersContext) && !headersContext.isEmpty()) {headersContext.forEach((key, values) -> values.forEach((value) -> {headers.addIfAbsent(key, value);}));}// 状态码添加到ServerHttpResponseif (nonNull(ResponseContext.getResponseCode())) {response.setStatusCode(ResponseContext.getResponseCode());}# 这里会报错return body;}
}

异常拦截GlobalExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)@ResponseBodypublic 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***

这篇关于getWriter() has already been called for this response的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/601494

相关文章

Tomcat启动报错:transport error 202: bind failed: Address already in use

Tomcat启动报错:transport error 202: bind failed: Address already in use 了,上网查找了下面这篇文章。也是一种解决办法。 下文来自:http://blog.csdn.net/sam031503/article/details/7037033 tomcat 启动日志报出以下错误:  ERROR: transport err

兔子-在as中删除项目以及删除后报错already disposed:Module:'haha'

1. 2.点左上角红色的减号,,Apply 3,删除setting.gradle中include中的要删除的项目 . 4.选择要删除的项目,,点击键盘的delete键 5.点击第二个图标。 删除成功!! 完全删除haha项目之后,仍然报这个错误。 解决办法:重启as

ZeroMQ(java)之Requerst/Response模式

自己最开始是在cloud foundry中接触过消息服务器(nats),或者说是消息中间件,也算是初步知道了一个消息服务器对于分布式的网络系统的重要性,后来自己也曾想过在一些项目中使用它,尤其是在一些分布式的环境下,可以极大的方便整个系统的实现。。。。 例如如下的形式: 在中间通过一个消息中间件,可以很方便的将各个woker的数据发送到最终的统计服务器来做数据的统计,从而

Address localhost:1099 is already in use:tomcat频繁重启端口占用问题

错误提示 Unable to open debugger port (127.0.0.1:58198): java.net.SocketException "Socket closed" Address localhost:1099 is already in use 端口被占用 报错原因 由于短时间内频繁运行tomcat服务器。 为了避免出现这一错误。可以点击刷新uodate

【Puppeteer】‘left‘ is already pressed, ‘${button}‘ is already pressed 的解决办法

解决过程如下 这是我原来的代码,不管我怎么修改,都一直会出现 'left' is already pressed 这个错误 找了很多资料 搜了 很多网站都 找不到解决办法 async function dragAndDrop(page, canvasSelector, startX, startY, endX, endY) {const startCoordinates = await ge

缓解webclient频繁报‘Connection prematurely closed BEFORE response’的问题

现象: 我在Java代码中使用org.springframework.web.reactive.function.client.WebClient进行网络请求,一开始会有比较多的偶发报错:Connection prematurely closed BEFORE response,网络连接莫名其妙就断了。 处理: 在网上找了挺多资料,就感觉https://stackoverflow.com/q

spark-shell启动报错:Yarn application has already ended! It might have been killed or unable to launch...

前半部分转自:https://www.cnblogs.com/tibit/p/7337045.html (后半原创) spark-shell不支持yarn cluster,以yarn client方式启动 spark-shell --master=yarn --deploy-mode=client 启动日志,错误信息如下   其中“Neither spark.yarn.ja

手写服务器httpserver_封装Response_封装Request_JAVA199-201

来源:http://www.bjsxt.com/ 一、S02E199_01手写服务器httpserver_封装Response <html><head><title>第一个表单</title></head><body><pre>method:请求方式 get/postget:默认方式,数据量小,安全性不高post:量大,安全性相对高action:请求的服务器路径id:编号,前端(用户的浏览器)

The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method 已解决

前面有个webSocket自动断开连接的问题,已解决,请见博客: webSocket java.io.EOFException: null 增加心跳机制解决 然后又报了一个错: java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid st

Error:(106) Attribute quot;rippleColorquot; has already been defined

compile 'com.github.navasmdc:MaterialDesign:1.5@aar' 扁平化设计,导入出现: Error:(106) Attribute "rippleColor" has already been defined 解决: compile 'com.github.navasmdc:MaterialDesign:1.3.2'