已为此响应调用 Tomcat 8.5 response.getWriter()

Posted

技术标签:

【中文标题】已为此响应调用 Tomcat 8.5 response.getWriter()【英文标题】:Tomcat 8.5 response.getWriter() has already been called for this response 【发布时间】:2019-08-18 00:19:42 【问题描述】:

我在生产环境中使用 Tomcat 8.5.23 和 Servlet(如果相关,还可以使用 Spring 自动装配功能) response.getWriter() 在生产中返回 null

在自定义过滤器中调用chain.doFilter(req, res); 时也会发生这种情况:

public class MyFilter implements Filter 
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        chain.doFilter(req, res);
  
  public void init(FilterConfig filterConfig) 
  public void destroy() 

例外:

Request processing failed; nested exception is java.lang.IllegalStateException: getWriter() has already been called for this response] with root cause
java.lang.IllegalStateException: getWriter() has already been called for this response
        at org.apache.catalina.connector.Response.getOutputStream(Response.java:591)
        at org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:194)
        at org.springframework.http.server.ServletServerHttpResponse.getBody(ServletServerHttpResponse.java:89)
        at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:106)
        at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:41)
        at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227)
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:247)
        at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:203)
        at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:113)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

我尝试添加HttpServletResponseWrapper,但没有成功

【问题讨论】:

在 tomcat 中实现的 HttpServletResponse 不能返回 null。有两种情况:1.getOutputStream()被调用->它会抛出IllegalStateException,2.内部写者为空:它将创建一个新的CoyoteWriter。可能某些过滤器正在包装响应对象并且不能正确处理某些情况。只需使用调试器单步执行过滤器链。绝对不是 tomcat 的问题。 @SvetlinZarev 这个问题只发生过几次,目前无法重现 【参考方案1】:

您的过滤器代码看起来不错,但问题出在其他地方。评论已经提到getWriter() 不能返回null。查看似乎发生这种情况的代码。代码可能会尝试将编写器分配给变量,但会捕获并忽略该异常。在异常被忽略后,有人尝试使用该变量,但它包含null,因为没有发生赋值。

可能发生这些“已调用”错误的一种常见情况是错误处理。 servlet 开始发送响应,因此称为getWriter()。然后它遇到错误,错误处理尝试写入错误响应,因此再次调用getWriter()。您无法重现该问题,因为该错误情况是随机发生的。

【讨论】:

但是问题不在于过滤器,afaict。 但是过滤器在 servlet 之前执行 您的过滤器执行 - 没有问题 - 然后调用 servlet。 servlet 遇到问题。您的过滤器甚至没有调用getWriter(),那么getWriter() 返回null 的问题怎么会在您的过滤器中实现?

以上是关于已为此响应调用 Tomcat 8.5 response.getWriter()的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot + tomcat 8.5 + mongoDB,AsyncRequestTimeoutException

Web入门系列初探HttpServletResponse

错误渲染视图:java.lang.IllegalStateException:已为此响应调用了getOutputStream()

在CentOS 7中安装与配置Tomcat-8.5方法

无法发送 Https 请求(在 SSLv3 中运行 Tomcat 8.5)

使用war将spring-boot和angular 7应用程序部署到tomcat 8.5中