IllegalStateException 的解决办法
公司一个老项目,这两天爆出了一个问题。异常都是
java.lang.IllegalStateException: getOutputStream() has already been called for this response
这个项目的内容,就是通过页面下载一个word文件,当然这个word文件是根据用户的选择动态生成的。
当时实现这个功能的人,没有用servlet 来实现这个功能,而是选择了使用 jsp, 然后在 jsp 当中调用了
一个自己做的 taglib,然后在 doStartTag 方法当中,将 word 内容往 OutputStream 里面写。
这个功能,以往都没发现什么大问题,但是最近有两个word文件下载不下来,一下载就说 连接被服务器重置了。
查异常就是上面提到的 IllegalStateException。
先搜了一下,果然是个比较常见的问题,google上一搜一大堆。
基本上都是说,在jsp里面,自己往 OutputStream 里面写东西,就容易产生这样的冲突。因为在jsp所生成
的对应的java文件中,可以很清楚的看到
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);
}
这个 releasePageContext 会去获取 writer,而这个时候 getOutputStream已经被调用了,就会出这个错误。
解决的方法有两种,一种是比较强的,直接 _jspxFactory = null; 另外一种比较委婉,
out.clear();pageContext.pushBody();
这两种方式,对于直接在 jsp里面往 OutputStream 写东西的情况,例如产生校验码的图片,是没有问题的。
但是,对于我这种在jsp里面调用了 tag 再写OutputStream的情况无效。
开始折腾jsp文件,把 out 又是clear又是clearBuffer,都没啥效果,于是冷静下来想这个问题。
因为不是每个文件都出错,而且呢,使用 out.clear();pageContext.pushBody();方法后,后台
没有异常了,但是还是一样的报告服务器重置了连接。也就是说,在jsp报告那个错误之前,实际上
已经出问题了。
这时候,注意到服务器没有告知浏览器word文件的长度,有可能是在某个word当中,出现了特殊的
字符,例如 \0 这样的东西,由于没有长度,浏览器认为已经下载完成了,于是连接就被中断了。所以,
我判断这个错误的原因,应该是由于没有设置长度所造成的。
接下来就简单了,把word文件写到一个临时文件当中,然后取得长度,在response当中设置文件长度,
一切就OK了。
结论:尽信google,不如无google。如果不是一开始走向了歧途,说不定能够较早的定位到问题。
上一篇: 反射中Method类的invoke() 和getMethod()
下一篇: MySQL搜索引擎总结