• 解决getWriter() has already been called for this response异常(转)


    近期,查看公司应用日志系统error错误信息时,发现了大量的nested exception is java.lang.IllegalStateException: getWriter() has already been called for this response异常。这个错误以前见到过,也解决过。于是想着趁有点空闲,总结下该错误。如有不对,望各位多包容,欢迎交流。

    一、应用日志文件中的错误信息

    ERROR 977 --- [io-8686-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [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:575) ~[tomcat-embed-core-8.5.5.jar:8.5.5]

    原因分析
    IllegalStateException: getWriter() has already been called for this response

            从字面意思不难得出错误原因:HttpServletResponse中的PrintWriter已经被手动调用过了。所以当servlet执行到方法结果处理逻辑时,需要将返回值输出到writer中去,这时发现PrintWriter已经被调用过。于是servlet认为这是使用混乱的逻辑错误,于是抛出错误。

            根本原因:在Controller接口方法中,既手动调用PrintWriter向客户端输出内容,又设置了方法返回值。导致servlet需要两次将结果通过PrintWriter输出到客户端,结果报错。

    /**1.反例:验证接口既手动调用PrintWriter输出流flush,又return 返回值.
    
     * 验证结果:客户端ajax请求正常返回,但同时,服务端出现异常,org.springframework.web.util.NestedServletException: Request processing failed;
    
     * nested exception is java.lang.IllegalStateException: getWriter() has already been called for this response
    
     * 结论:方法内已经执行过response输出流write动作.
    
     * servlet再次通过response输出流将返回值向客户端发送时,发现输出流已经被调用过,也就是getWriter()过。于是认为这是使用逻辑混乱,果断报错。
    
     * */
    
    @RequestMapping(value="/checkGetWriterError", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    
    @ResponseBody
    
    public ServiceResponse<String> checkGetWriterError(HttpServletResponse response) throws Exception {
    
        log.info("验证接口既手动调用输出流flush,又return 返回值.造成异常!");
    
        PrintWriter printWriter = response.getWriter();
    
        printWriter.write(ServiceResponse.ok("来自printWriter的返回值").toString());
    
        printWriter.flush();//没有该句也是报一样错.
    
        return ServiceResponse.ok("成功了,恭喜你.");
    
    }

    结果:程序正常返回结果,控制台出现异常。

    (返回结果中编码问题,不在本文讨论范围,请忽略)

     源码佐证

    二、扩展验证附验证结果

    • 验证PrintWriter输出流flush,无返回值

    /**2.正例:验证接口仅手动调用PrintWriter输出流flush,无返回值.*/
    
    @RequestMapping(value="/checkGetWriterError2", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    
    @ResponseBody
    
    public void checkGetWriterError2(HttpServletResponse response) throws Exception {
    
        log.info("验证接口手动调用PrintWriter输出流, 无return 返回值. 接口正常执行无异常!");
    
        PrintWriter printWriter = response.getWriter();
    
        printWriter.write(ServiceResponse.ok("来自printWriter的返回值").toString());
    
        printWriter.flush();
    
    }

    结果:程序正常返回结果,控制台无异常。

    (返回结果中编码问题,不在本文讨论范围,请忽略)

    调用ServletOutputStream输出流flush,  无返回值

    /**3.正例:验证接口既手动调用ServletOutputStream输出流flush,  无返回值.*/
    
    @RequestMapping(value="/checkGetWriterError3", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    
    @ResponseBody
    
    public void checkGetWriterError3(HttpServletResponse response) throws Exception {
    
    log.info("验证接口手动调用ServletOutputStream输出流, 无return 返回值. 接口正常执行无异常!");
    
        ServletOutputStream output = response.getOutputStream();
    
        output.write(ServiceResponse.ok("来自ServletOutputStream的返回值").toString().getBytes());
    
        output.flush();
    
    }

    结果:程序正常返回结果,控制台无异常。

    调用ServletOutputStream输出流flush,return 返回值

    /**4.反例:验证接口既手动调用ServletOutputStream输出流flush,又return 返回值.*/
    
    @RequestMapping(value="/checkGetWriterError4", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    
    @ResponseBody
    
    public ServiceResponse<String> checkGetWriterError4(HttpServletResponse response) throws Exception {
    
    log.info("验证接口手动调用ServletOutputStream输出流, 又执行return 返回值. 接口返回异常!");
    
        ServletOutputStream output = response.getOutputStream();
    
        output.write(ServiceResponse.ok("来自ServletOutputStream的返回值").toString().getBytes());
    
        output.flush();
    
        return ServiceResponse.ok("来自return的返回值.");
    
    }

    结果:程序返回结果不正常,控制台无异常。

    不仅ServletOutputStream输出流中的内容被发送到客户端,而且方法返回结果也输出到客户端。

    ————————————————
    版权声明:本文为CSDN博主「常乐_smile」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/li396864285/article/details/78122296

  • 相关阅读:
    【洛谷P2839】middle
    【洛谷P2495】消耗战
    【CF1438D】Powerful Ksenia
    【CF878E】Numbers on the blackboard
    【洛谷U138580】简单的打击
    【洛谷P4774】屠龙勇士
    【GMOJ5363】生命之树
    【YbtOJ#20075】区间异或
    【YbtOJ#20077】计划带师
    hdu 2688
  • 原文地址:https://www.cnblogs.com/muxi0407/p/12094935.html
Copyright © 2020-2023  润新知