2010-05-17 5 views
4

J'ai une application web simple (Servlet, JSP, et JSTL) dont la fonctionnalité principale est l'affichage des images récupérées à partir d'un serveur principal. La servlet du contrôleur transfère l'utilisateur à une JSP qui à son tour utilise une autre servlet pour afficher l'image résultante sur cette même JSP. Plus bas, la JSP a une ligne semblable à:Comment gérer les exceptions d'une servlet générant des images?

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

qui invoque une requête GET sur la servlet-génération d'image amenant à générer l'image.

Ma question est: comment gérer les exceptions émises par ce servlet générant des images? J'ai déjà une page d'erreur définie (dans web.xml) pour gérer ServletException dans mon application Web, mais cela ne fonctionne pas pour ce servlet générant des images, et les erreurs suivantes apparaissent dans mes journaux de serveur 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 

Quel est mon recours dans cette situation? J'aimerais pouvoir gérer les exceptions générées par ce servlet générant des images et afficher une erreur sur l'interface utilisateur principale ou rediriger l'utilisateur vers une autre page d'erreur.

Répondre

3

Vous ne pouvez pas modifier la réponse pour rediriger vers une page d'erreur tandis que envoyant la réponse. Il est déjà trop tard pour changer toute la réponse. Vous ne pouvez pas demander aux octets déjà envoyés du côté client. C'est ce que le IllegalStateException signifie ici. C'est un point de non-retour. La meilleure solution consiste à simplement enregistrer l'exception ou à réécrire le code afin qu'il n'écrive aucun bit dans la réponse (sans définir les en-têtes de réponse) alors que la logique métier n'a pas terminé ses opérations. tâche encore. Une fois que vous avez déterminé que la logique métier n'a généré aucune exception, commencez à écrire (et donc indirectement à valider) la réponse. Si la logique métier a déclenché une exception alors que la réponse n'est pas encore effleurée, vous pouvez la lancer en toute sécurité afin qu'elle se retrouve dans une page d'erreur. Bien que dans le cas d'une servlet d'image, vous pouvez également diffuser un certain standard 404.gif à la réponse à la place. Cela parce que vous ne pouvez pas afficher une autre page HTML (erreur) dans un élément <img> et vous ne pouvez également pas modifier l'URL de la page JSP/HTML parent, car cela concerne une requête différente.

+0

Merci pour l'explication - c'est logique maintenant! J'aimerais pouvoir diffuser une image 404.gif en conserve; Le problème est que mon Servlet d'image peut renvoyer un fichier GIF, PNG, TIFF ou PDF - ce qui fait que quelques images conservées pour un seul type d'exception - la logique métier peut déclencher l'une des trois exceptions lors de la génération d'une image. J'aime votre idée de ne rien écrire à la réponse jusqu'à ce que je suis sûr à 100% que la logique métier n'a pas jeté une exception. – ssahmed555

+0

Réglez simplement l'en-tête 'Content-Type' en fonction de l'extension de l'image. Vous pouvez soit le réparer pour le '404.gif' ou simplement utiliser 'getServletContext(). GetMimeType (filename)' pour cela. Vous pouvez obtenir quelques idées sur [cet article] (http://balusc.blogspot.com/2007/04/imageservlet.html). – BalusC

0

D'abord, identifiez pourquoi l'exception d'état illégal est levée. Plutôt que de gérer une exception levée, vous voulez probablement simplement corriger votre code afin qu'il disparaisse.

1

Selon l'API de servlet, aucune servlet ne doit appeler getWriter() et getOutputStream() sur le même objet de réponse que celui qui provoque l'exception IllegalStateException. Habituellement, c'est la source de cette exception. Si vous produisez des données binaires comme et un fichier image, vous devez utiliser getOutputStream().

+1

appel à la fois 'getWriter()' et 'getOutputStream()' produit en effet aussi un 'IllegalStateException', mais avec un message complètement différent comme 'getWriter a déjà été appelé pour cette réponse'. Ce n'est donc pas le problème ici. – BalusC

+0

Ma servlet générant une image n'appelle que getOutputStream(). Donc, ce n'est pas pourquoi je reçois le IllegalStateException. – ssahmed555

1

On dirait que le problème que vous avez est dans votre ExceptionPage.jsp, pas votre code de servlet.

Et ce

java.lang.IllegalStateException: Impossible de réinitialiser le tampon après la réponse a été commise

signifie que vous avez déjà essayé d'envoyer une réponse. Vous avez probablement ouvert un flux de sortie directement et y avez écrit des données. Une fois que vous l'avez fait, vous ne pouvez pas essayer de définir les en-têtes et autres sur une réponse (ils sont déjà en route vers le client).

Vous devez améliorer la gestion de l'état. Le meilleur moyen de le faire est de séparer le prétraitement des demandes de la génération de réponse. Une fois que vous écrivez réponse, vous pouvez seulement faire ou mourir. Pour cela, vérifiez que vous n'attrapez pas d'IOExceptions dans la sortie de la réponse, en les enveloppant dans ServletException et que vous les redirigez vers votre page d'erreur. Vous ne pouvez vraiment pas les gérer dans le contexte de la demande actuelle.

+0

Vous avez raison - J'ai déjà défini le type de contenu et ouvert le OutputStream au moment où l'exception se produit. Vous avez raison: j'ai besoin de retravailler la servlet génératrice d'images. – ssahmed555

0

Vous devez attraper l'exception et transmet la demande à l'aide RequestDispatcher à la page souhaitée:

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

Il a déjà une 'error-page' définie dans' web.xml' qui fait essentiellement la même chose mais c'est une meilleure pratique. Tout le problème est seulement qu'il était incapable d'afficher cette page d'erreur. – BalusC

+0

Merci pour clarifier, votre réponse a beaucoup de sens maintenant. – Snehal

Questions connexes