2016-09-10 3 views
0

Hier ist mein Anwendungsfall:Jersey: Ist es möglich, den Rückgabetyp des Jersey-Filters() zu überschreiben?

Ich habe einen Jersey-Filter public void filter(ContainerRequestContext requestContext){ //do stuff } implementiert, der alle eingehenden Anfragen auf alle Jersey-Endpunkte abfangen wird, die ich registriert habe. Basierend auf einiger Validierung I der eingehenden Request-Header zu tun, ich in der Lage gewesen, eine Anfrage über die folgenden abzulehnen:

Response response = Response.status(status).entity(errorMsg).build(); 
requestContext.abortWith(response); 

Dies ist, wie ich es getan und es hat für mich gearbeitet. Jetzt muss ich jedoch auf bestimmte Informationen im requestContext innerhalb des tatsächlich angeforderten Endpunkts zugreifen. Ich weiß, das kann wie so geschehen:

@Path("/path") 
@GET 
public ReturnType endpoint(@Context ContainerRequestContext requestContext, 
          @CookieParam("cookieId") String cookieValue, 
          @HeaderParam("headerId") String headerValue, etc..){ 
    //do stuff 
} 

Das Problem ist, wenn ich die oben tun^die Anfrage Informationen über den Endpunkt zugreifen zu können, kann ich nicht mehr die Anforderung in den Filter abbrechen, wenn der Filter die Validierung fehlschlägt weil ich die folgende Fehlermeldung erhalten:

java.lang.IllegalStateException: The request cannot be aborted as it is 
already in the response processing phase. 

es scheint, dass, wenn Sie irgendeine Art von Parametern auf Jersey Endpunkte definieren, die innerhalb des ContainerRequestContext zugegriffen werden kann, wird es nicht zulassen, dass Sie die Filterkette innerhalb des Filters abzubrechen.

Eine Arbeit rum (die ich noch nicht ausprobiert habe, aber vorausgesetzt, wird funktionieren), wäre dies: Anstatt zu versuchen, die Anfrage innerhalb des Filters abzubrechen, wenn die Filtervalidierung fehlschlägt, kann ich einfach einen benutzerdefinierten Header hinzufügen um die Anfrage. Auf dem Endpunkt selbst kann ich dann prüfen, ob dieser Header gesetzt ist. Wenn es gesetzt ist, weiß ich, dass die Filtervalidierung fehlgeschlagen ist, und dann kann ich ein Response Objekt erstellen und das zurückgeben. Wenn es nicht gesetzt ist, weiß ich, dass die Filtervalidierung erfolgreich war, und ich kann weitermachen und die Anfrage bearbeiten.

Um zu vermeiden, dass dies manuell an jedem einzelnen Jersey-Endpunkt, den ich habe (daher der Punkt der Filter), zu tun, wäre es schön, einfach die Anfrage am Filter zu stoppen und die Antwort direkt dort zurück/abzubrechen. Ich dachte, das war der ganze Sinn von Filtern an erster Stelle. Der Rückgabetyp der Jersey-Filtermethode ist jedoch void, und ich kann das anscheinend nicht überschreiben.

Wer eine Lösung für meinen dilemna hat?

+0

Vielleicht so etwas wie [dieser] (http: // Stackoverflow.com/a/27666797/2587435) anstatt den gesamten Anfragekontext zu bekommen –

+0

Danke, aber ich habe herausgefunden, was ich falsch gemacht habe. Wird in einer Antwort schreiben. – bscott

Antwort

0

herausgefunden, was die Wurzel des Problems war. Mein Filter war eine Antwort-Filter, wie die folgenden sah:

class ResponseFilter implements ContainerResponseFilter{ 
    public void filter(ContainerRequestContext requestContext, 
         ContainerResponseContext responseContext){ 
     MultivaluedMap<String, Object> headers = responseContext.getHeaders(); 
     headers.add("Access-Control-Allow-Origin", "http://localhost:9000"); 
     headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); 
     headers.add("Access-Control-Allow-Headers", "Content-Type"); 
     headers.add("Access-Control-Allow-Credentials", "true"); 
     if(requestValidationFailed){ 
      Response response = Response.status(status).entity(error).build(); 
      requestContext.abortWith(response); 
     } 
    } 
} 

Wie Sie aus dem obigen Codebeispiel sehen können, bin ich bereits definiert, die Response-Header, bevor ich auf die Überprüfungsanforderung Validierung erhalten. Auf diese Weise geht Jersey davon aus, dass ich mich jetzt in der "Antwortverarbeitungsphase" befinde. Es macht Sinn, dass ich die Anfrage nicht abbrechen kann, wenn ich bereits Header für eine Antwort einstelle.

Es könnten auch andere Möglichkeiten, dieses Problem zu lösen, aber ich löste es durch meine Filter in zwei Filter (zwei getrennte Klassen) aufgeteilt wird.

class RequestFilter implements ContainerRequestFilter{ 
    public void filter(ContainerRequestContext requestContext){ 
     if(requestValidationFailed){ 
      Response response = Response.status(status).entity(error).build(); 
      requestContext.abortWith(response); 
     } 
} 

class ResponseFilter implements ContainerResponseFilter{ 
    public void filter(ContainerRequestContext requestContext, 
         ContainerResponseContext responseContext){ 
     MultivaluedMap<String, Object> headers = responseContext.getHeaders(); 
     headers.add("Access-Control-Allow-Origin", "http://localhost:9000"); 
     headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); 
     headers.add("Access-Control-Allow-Headers", "Content-Type"); 
     headers.add("Access-Control-Allow-Credentials", "true"); 
    } 
} 

Ich kann jetzt @Context, @CookieParam, @HeaderParam usw. Parameter in meine Ressourcenklasse-Funktionen übergeben, ohne dass die java.io.IllegalStateException zu bekommen. Die Filterkette wird ebenfalls erfolgreich abgebrochen, wenn meine requestValidationFailed-Prüfung true zurückgibt und die Ressourcenfunktion nie aufgerufen wird.

Verwandte Themen