2010-05-17 55 views
4

我有一个简单的(Servlet,JSP和JSTL)Web应用程序,其主要功能是显示从后端服务器检索的图像。控制器servlet将用户转发给JSP,然后JSP使用另一个Servlet在相同的JSP上显示结果图像。再往下,在JSP具有类似于行:如何处理来自图像生成Servlet的异常?

<a href="<c:out value='${imageURL}'/>"><img src="<c:out value='${imageURL}'/>" alt="image view" border="1"></a> 

其中调用了图像生成的servlet使其产生图像的GET请求。

我的问题是:如何处理由此图像生成servlet引发的异常?

我已经定义了一个错误页面(在web.xml中)来处理我的web应用程序中的ServletException,但这不适用于此图像生成Servlet,并导致在我的Tomcat服务器日志中显示以下错误:

SEVERE: Exception Processing ErrorPage[exceptionType=javax.servlet.ServletException, location=/WEB-INF/ExceptionPage.jsp] 
java.lang.IllegalStateException: Cannot reset buffer after response has been committed 

在这种情况下我的追求是什么?

我希望能够处理从此图像生成Servlet抛出的异常,并在主UI上显示一些错误或将用户转发到另一个错误页面。

回答

3

您不能将响应更改为重定向到错误页面,而发送响应。现在改变整个响应已经太晚了。你不能要求那些已经从客户端发回的字节。这就是IllegalStateException代表的地方。这是一个不归路。

你可以做的最好的事情就是记录异常,或者重写代码,以便在业务逻辑还没有完成的时候它不会写任何位给响应(也不会设置响应头)任务呢。一旦你确定业务逻辑没有抛出任何异常,那么就开始写(并因此间接地提交)响应。如果业务逻辑在响应尚未触及时抛出异常,那么您可以安全地将其抛出,以便在错误页面中结束。尽管在图像servlet的情况下,您可能还想将一些标准的404.gif串流到响应中。这是因为您不能在<img>元素中显示另一个HTML(错误)页面,并且也不能更改父JSP/HTML页面的URL,因为这涉及到不同的请求。

+0

感谢您的解释 - 现在有道理!我希望能够流传一个罐头404.gif图像;问题在于我的图像Servlet可能会返回GIF,PNG,TIFF或PDF - 因此,只有一种类型的异常会生成很多图像 - 商业逻辑在生成图像时可能会抛出三种异常中的任何一种。 我喜欢你的想法,不写任何东西到响应,直到我100%确定业务逻辑没有抛出异常。 – ssahmed555 2010-05-17 19:18:32

+0

只需根据图像扩展名设置“Content-Type”标头即可。你可以为'404.gif'修复它,或者使用'getServletContext()。getMimeType(filename)'来做这件事。您可以从[本文](http://balusc.blogspot.com/2007/04/imageservlet.html)中获得一些想法。 – BalusC 2010-05-17 19:19:30

0

首先,确定为什么抛出非法状态异常。与其处理抛出的异常,你可能只想修复你的代码,使其消失。

1

根据servlet API,没有servlet应该在同一个响应对象上调用getWriter()和getOutputStream(),因为它会导致IllegalStateException。通常这是这个例外的来源。如果你输出二进制数据像图像文件,你应该使用getOutputStream()。

+1

调用两个'的getWriter()'和'的getOutputStream()'确实也产生'IllegalStateException',但与完全不同的信息,比如'getWriter已经被调用了这个响应'。这在这里不是问题。 – BalusC 2010-05-17 19:04:15

+0

我的图像生成Servlet只调用getOutputStream()。所以这不是我得到IllegalStateException的原因。 – ssahmed555 2010-05-17 19:07:46

1

看起来像你的问题是在你的ExceptionPage.jsp中,而不是你的servlet代码。

java.lang.IllegalStateException:响应已 一直致力于你已经试图发送一个响应

手段后 不能复位缓冲区。 也许你已经直接打开了一个输出流并向它写了一些数据。一旦你完成了它,你就不能尝试在响应中设置标题等等(它们已经到了客户端)。

你需要做一个更好的状态管理。最好的办法是将请求预处理与响应生成分开。一旦你写回应,你只能做或死。为此,请检查您是否从响应输出中捕获IOExceptions,将它们封装到ServletException并将它们重定向到错误页面。你真的无法在当前请求的上下文中处理它们。

+0

正确的是 - 我已经设置了内容类型,并在发生异常时打开OutputStream。 你说得对:我需要重新制作图像生成servlet。 – ssahmed555 2010-05-17 19:10:08

0

你应该捕捉异常,并且使用的RequestDispatcher到所需的页面转发请求:

public void doGet(HttpServletRequest request, 
       HttpServletResponse response) 
throws ServletException, IOException { 

// The following piece of code results in NumberFormatException which will 
// be detected by the container. The RequestDispatcher object will forward 
// the same request to the other resource, here the file: forwardedJSP.jsp 
try { 
    int test = Integer.parseInt("abc"); 
} catch (NumberFormatException nfe) { 
    RequestDispatcher rd = request.getRequestDispatcher("/forwardedJSP.jsp"); 
    rd.forward(request, response); 
}} 
+0

他已经在'web.xml'中定义了一个'error-page',它基本上和这个一样,但是更好的做法。整个问题只是他无法显示这个错误页面。 – BalusC 2010-05-17 19:11:23

+0

感谢您澄清,您的答案现在很有意义。 – Snehal 2010-05-17 19:24:39