getOutputStream() has already been called for this

摘自:http://cid-e1a9d43fd56a4641.spaces.live.com/Blog/cns!E1A9D43FD56A4641!114.entry
java.lang.IllegalStateException: getOutputStream() has already been called for this response
tomcat有此现象,weblogic下没有
原因:
在tomcat中jsp编译成servlet之后在函数_jspService(HttpServletRequest request, HttpServletResponse response)的最后有一段这样的代码
finally{
if (_jspxFactory != null)
_jspxFactory.releasePageContext(_jspx_page_context);
}
这里是在释放在jsp中使用的对象,会调用response.getWriter(),因为这个方法是和responsegetOutputStream()相冲突的!所以会出现以上这个异常。
解决办法:
在使用完输出流以后调用以下两行代码即可:
out.clear();
out = pageContext.pushBody();

API:
public java.io.PrintWriter getWriter()
throws java.io.IOException
Returns a PrintWriter object that can send character text to the client. The PrintWriter uses the character encoding returned by getCharacterEncoding(). If the response's character encoding has not been specified as described in getCharacterEncoding (i.e., the method just returns the default value ISO-8859-1), getWriter updates it to
ISO-8859-1. Calling flush() on the PrintWriter commits the response.
Either this method or getOutputStream() may be called to write the body, not both.
Returns:
a PrintWriter object that can return character data to the client
Throws:
UnsupportedEncodingException - if the character encoding returned by getCharacterEncoding cannot be used
java.lang.IllegalStateException - if the getOutputStream method has already been called for this response object
java.io.IOException - if an input or output exception occurred
See Also:
getOutputStream(), setCharacterEncoding(java.lang.String)
如API所言,由于ServletResponse.getOutputStream()方法和该方法都有可能被调用,来输出JSP页面的内容,如果其中的一个方法被调用了,再调用另一个方法就会抛
出异常。
解决方法如下:
out.clear():清空缓存的内容。
pageContext.pushBody():参考API

public BodyContent pushBody()
Return a new BodyContent object, save the current "out" JspWriter, and update the value of the "out" attribute in the page scope attribute namespace of the PageContext.
Returns: the new BodyContent
·返回一个新的BodyContent(代表一个HTML页面的BODY部分内容)
·保存JspWriter实例的对象out
·更新PageContext的out属性的内容

This exception also may caused by there are some space character between <%..%> and <%..%> in jsp.
### 关于 'getOutputStream() has already been called for this response' 错误的解决方案 #### 问题分析 `getOutputStream()` 和 `getWriter()` 是 Java Servlet 中用于向客户端发送响应数据的方法。根据 Servlet 规范,对于同一个 `HttpServletResponse` 对象,这两个方法不能同时被调用[^3]。一旦其中一个方法被调用,再次尝试调用另一个方法将会引发 `IllegalStateException` 异常。 具体来说,当程序试图通过以下方式访问响应对象时会发生冲突: - 调用了 `response.getOutputStream()` 后再调用 `response.getWriter()`。 - 或者相反顺序:先调用 `response.getWriter()` 再调用 `response.getOutputStream()`。 这通常发生在混合使用字符流(`PrintWriter`)和字节流(`ServletOutputStream`)的情况下,尤其是在自定义过滤器或拦截器中处理请求/响应时容易出现问题[^1]。 --- #### 解决方案 以下是几种常见的解决办法: ##### 方法一:统一使用一种输出方式 确保在同一逻辑单元内只使用单一类型的输出流。例如,如果需要返回二进制数据,则始终使用 `response.getOutputStream()`;如果是纯文本或其他基于字符串的数据,则仅使用 `response.getWriter()`。 示例代码展示如何正确设置并写入数据到响应中: ```java @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应头信息 response.setContentType("text/html;charset=UTF-8"); try (PrintWriter out = response.getWriter()) { // 使用字符流 out.println("<html><body>"); out.println("<h1>Hello World</h1>"); out.println("</body></html>"); } } ``` 或者针对文件下载场景下的字节流操作: ```java @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String filePath = "/path/to/file"; File file = new File(filePath); response.reset(); response.setBufferSize(DEFAULT_BUFFER_SIZE); response.setContentType(getServletContext().getMimeType(file.getName())); response.setHeader("Content-Length", String.valueOf(file.length())); response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\""); BufferedInputStream input = null; BufferedOutputStream output = null; try { input = new BufferedInputStream(new FileInputStream(file)); output = new BufferedOutputStream(response.getOutputStream()); byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; int bytesRead; while ((bytesRead = input.read(buffer)) != -1) { output.write(buffer, 0, bytesRead); } output.flush(); } finally { if (output != null) output.close(); if (input != null) input.close(); } } ``` 以上两个例子分别展示了如何单独依赖字符流或字节流完成任务而不会触发非法状态异常[^4]。 --- ##### 方法二:清除缓冲区内容 某些情况下可能会遇到第三方库自动注入了额外的内容至响应体中从而间接导致重复调用情况发生。此时可以通过清理现有缓冲区的方式来规避潜在风险。 下面是一个简单的实现片段: ```java @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { response.getOutputStream(); // 假设这里已经初始化了一个字节流... } catch (IllegalStateException e) {} // 清除任何已存在的未提交输出 response.resetBuffer(); // 接着安全地切换回字符模式 PrintWriter writer = response.getWriter(); writer.print("Custom Message"); writer.flush(); return true; } ``` 注意这种方法虽然可以缓解部分特殊情形下产生的矛盾但仍需谨慎对待因为重置行为可能会影响其他组件预期效果。 --- ##### 方法三:检查是否有外部干扰 有时并非开发者自己显式调用了这些函数而是框架内部机制所致。因此建议仔细审查整个项目结构特别是那些涉及全局配置的地方比如Spring MVC中的Interceptor链表定义或是Filter注册过程是否存在不当之处引起连锁反应最终造成上述现象出现[^2]。 --- ### 总结 综上所述,“getOutputStream() has already been called for this response”的根本原因是违反了Servlet API的设计原则——不允许交替使用两种不同形式的输出通道。要彻底解决问题可以从以下几个方面入手:一是严格控制编程习惯坚持选用固定的输出手段;二是必要时借助工具类辅助管理资源释放流程减少人为失误概率;三是深入排查环境因素排除隐匿隐患点提升系统的健壮性和稳定性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值