2013-02-08 14 views
6

Sto lavorando a un'app Jetty/RESTEasy. Se lancio uno WebApplicationException(myResponse) da uno dei miei endpoint REST, invia la risposta data al client.Come si gestiscono gli stati di errore nei filtri del servlet senza mostrare all'utente una traccia dello stack?

Quando un filtro rileva un errore, voglio lo stesso comportamento:

  1. Deve interrompere l'esecuzione di procedere, e
  2. Dovrebbe dare all'utente una chiara, errore di formato JSON che non include una traccia dello stack.

Ovviamente, appena iscritto al flusso di risposta e return ing opere all'interno del metodo doFilter. Ma questo non funziona per altri metodi chiamati da doFilter.

Lanciare qualsiasi eccezione soddisferà la condizione n. 1 ma non ho ancora trovato un modo corretto per soddisfare la condizione n. 2. (Puoi vedere il mio miglior tentativo in basso.)

Come la Percezione ha spiegato nella sua risposta, WebApplicationException s sono trattati come qualsiasi altra eccezione nel contesto di un Filtro, e quindi forniscono all'utente una bella traccia di stack orribile.

Quindi, per riassumere le mie domande:

  • fare contenitori serveltt hanno alcun equivalente a throw new WebApplicationException(Response)?
  • E forse ancora più importante, come gestiscono altri progetti Java?

Ho questo codice in un filtro e funziona, ma io preferirei una soluzione più elegante che si applica automaticamente a tutti i filtri:

public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { 
    try { 
     doFilterOrThrow(request, response, chain); 
    } catch (WebApplicationException e) { 
     Response res = e.getResponse(); 
     ((HttpServletResponse) response).sendError(res.getStatus(), (String) res.getEntity()); 
    } 
} 

risposta

7

Il trattamento specifico si parla di eccezioni di applicazione web è solo definito nel contesto di un contenitore JAX-RS, che, a proposito, è non la stessa cosa di un contenitore Servlet.

I filtri Web sono gestiti dal contenitore Servlet, che non conosce o cura che un contenitore JAX-RS esista nello stesso server applicazioni. Inoltre, non conosce né cura le eccezioni delle applicazioni Web. Quindi, quando si lancia il WAE dal filtro, viene trattato come qualsiasi altra eccezione (errore del server con una traccia dello stack o una pagina di errore preconfigurata se ne si imposta uno nell'applicazione Web).

Mi sembra che se si indica un errore al client, è possibile farlo semplicemente dal filtro, scrivendo direttamente nel flusso di risposta. Ma se stai cercando di sfruttare alcune logiche JAX-RS esistenti, allora una soluzione (RESTEasy specifica) sarebbe quella di contrassegnare la richiesta come errata nel tuo filtro, quindi generare un WAE in JAX-RS, usando una classe provider. Esempio:

@WebFilter(urlPatterns = "*") 
public class ForwardingFilter implements Filter { 

    @Override 
    public void destroy() { 
     return; 
    } 

    @Override 
    public void doFilter(final ServletRequest request, 
      final ServletResponse response, final FilterChain chain) 
      throws IOException, ServletException { 
     // Add an error response to be processed by the JAX-RS container. 
     // This would obviously be based on some condition. 
     request.setAttribute("errorResponse", 
       Response.status(500).entity("Didn't work out!").build()); 
     chain.doFilter(request, response); 
    } 

    @Override 
    public void init(FilterConfig arg0) throws ServletException { 
     return; 
    } 
} 

@Provider 
@ServerInterceptor 
@HeaderDecoratorPrecedence 
@RequestScoped 
public class ForwardingHandlerProvider implements PreProcessInterceptor { 

    @Override 
    public ServerResponse preProcess(final HttpRequest request, 
      final ResourceMethod method) throws Failure, 
      WebApplicationException { 
     final Response errorResponse = (Response) request 
       .getAttribute("errorResponse"); 
     if (errorResponse != null) 
      throw new WebApplicationException(errorResponse); 
     return null; 
    } 
} 

Dal momento che il fornitore esiste in terra JAX-RS, l'eccezione di applicazione web viene elaborato in base alle regole della sezione 3.3.4 della specifica JAX-RS, e si ottiene la risposta desiderata nel client lato.

* EDIT: *

La linea di fondo è, non c'è Java EE modo standard prescritto (al momento) per gestire le eccezioni servlet in modo centralizzato simile a ciò che è disponibile in JAX-RS. Tuttavia, poiché si utilizza JBoss/RestEASY, è possibile utilizzare la libreria JBoss Seam Catch per avvicinarsi.

@HandlesExceptions 
public class ExceptionHandler { 
    public void handleServletException(
      final @Handles @WebRequest CaughtException<ServletException> caught, 
      @Context final HttpServletResponse response) { 
     try { 
      response.sendError(500, "An error occured"); 
     } catch (final IOException ioe) { 
      System.err.println("Dumb IO Exception: " + ioe); 
     } 
    } 
} 

Quanto sopra illustra un gestore di eccezioni, come descritto nella Seam Catch documentation. Nota che la libreria è in enorme flusso in questo momento, quindi vorrai utilizzarla solo come ultima risorsa.

+0

Grazie per le informazioni, penso di aver capito il problema un po 'meglio ora. Tuttavia, per chiarire: sto cercando un modo per scrivere entrambi nel flusso di risposta e * interrompere tutte le successive esecuzioni *. L'app su cui sto lavorando ha più filtri e alcuni di essi dipendono dai dati del precedente. Potrei semplicemente 'return' dal metodo' doFilter() ', ma questo non funziona se lo stato di errore viene rilevato in qualche altro metodo che chiama' doFilter() '. (Almeno non senza logica aggiuntiva ...) –

+0

Se è necessario interrompere immediatamente l'elaborazione, in pratica è necessario replicare, nel filtro, i dati che *** *** sarebbero stati restituiti da JAX-RS. Semplicemente non c'è altro modo, poiché i filtri non vengono eseguiti nel contenitore JAX-RS (ma piuttosto prima di esso). Un'altra opzione sarebbe quella di implementare la logica del filtro nell'intercettore di pre process, anche se ho la sensazione che ci siano filtri e processi intermedi che si sta tentando di saltare prima di quel punto. – Perception

+0

C'è un modo per impostare un gestore di errori generico per qualsiasi errore che si verifica nel contenitore del servlet, incluso nei filtri? - In realtà, penso che questo potrebbe essere ciò di cui ho bisogno: http://stackoverflow.com/questions/4207586/error-handler-servlet-how-to-get-exception-cause –