Frage

Ich lerne JAX-RS (aka, JSR-311) unter Verwendung von Jersey. Ich habe successfuly eine Root-Ressource erstellt und spiele um mit den Parametern:

@Path("/hello")
public class HelloWorldResource {

    @GET
    @Produces("text/html")
    public String get(
        @QueryParam("name") String name,
        @QueryParam("birthDate") Date birthDate) {

         // Return a greeting with the name and age
    }
}

Dies funktioniert gut, und behandelt jedes Format in der aktuellen Locale, die durch das Datum (String) Konstruktor verstanden wird (wie YYYY / MM / TT und TT / MM / JJJJ). Aber wenn ich einen Wert liefern, die ungültig oder nicht verstanden ist, erhalte ich eine 404-Antwort.

Zum Beispiel:

GET /hello?name=Mark&birthDate=X

404 Not Found

Wie kann ich dieses Verhalten anpassen? Vielleicht eine andere Antwortcode (wahrscheinlich „400 Bad Request“)? Was ist eine Fehlerprotokollierung? Vielleicht eine Beschreibung des Problems ( „schlechtes Datumsformat“) in einem benutzerdefinierten Header hinzufügen Fehlersuche zu unterstützen? Oder gibt eine ganze Fehlerreaktion mit Details, zusammen mit einem 5xx-Statuscode?

War es hilfreich?

Lösung

Es gibt mehrere Ansätze, um die Fehlerbehandlung Verhalten mit JAX-RS anpassen. Hier sind drei der einfacheren Möglichkeiten.

Der erste Ansatz ist eine Exception-Klasse zu erstellen, die WebApplicationException erstreckt.

Beispiel:

public class NotAuthorizedException extends WebApplicationException {
     public NotAuthorizedException(String message) {
         super(Response.status(Response.Status.UNAUTHORIZED)
             .entity(message).type(MediaType.TEXT_PLAIN).build());
     }
}

Und diese neu werfen erstellen Exception Sie einfach:

@Path("accounts/{accountId}/")
    public Item getItem(@PathParam("accountId") String accountId) {
       // An unauthorized user tries to enter
       throw new NotAuthorizedException("You Don't Have Permission");
}

Beachten Sie, brauchen Sie nicht die Ausnahme zu erklären, in einer throws-Klausel, weil WebApplicationException eine Laufzeitausnahme ist. Dies wird wieder eine 401-Antwort an den Client.

Der zweite und einfacher Ansatz ist es, einfach eine Instanz des WebApplicationException direkt im Code zu konstruieren. Dieser Ansatz funktioniert, solange Sie müssen nicht Ihre eigene Anwendung Ausnahmen implementieren.

Beispiel:

@Path("accounts/{accountId}/")
public Item getItem(@PathParam("accountId") String accountId) {
   // An unauthorized user tries to enter
   throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}

Dieser Code zu gibt ein 401 an den Client.

Natürlich ist dies nur ein einfaches Beispiel. Sie können die Ausnahme viel komplexer, wenn nötig machen, und Sie können generieren, was immer http-Antwort-Code, den Sie benötigen.

Ein weiterer Ansatz ist es, eine bestehende Ausnahme wickeln, vielleicht ein ObjectNotFoundException mit einer kleinen Wrapper-Klasse, die die ExceptionMapper Schnittstelle mit einer @Provider Anmerkung kommentierte implementiert. Dies teilt die JAX-RS-Laufzeit, dass, wenn die verpackte Ausnahme ausgelöst wird, den Antwortcode zurück im ExceptionMapper definiert.

Andere Tipps

@Provider
public class BadURIExceptionMapper implements ExceptionMapper<NotFoundException> {

public Response toResponse(NotFoundException exception){

    return Response.status(Response.Status.NOT_FOUND).
    entity(new ErrorResponse(exception.getClass().toString(),
                exception.getMessage()) ).
    build();
}
}

oben Klasse erstellen. Dies wird 404 (NotFoundException) handhaben und hier in toResponse Methode können Sie Ihre eigene Antwort geben. Ebenso gibt es ParamException etc., die den Kundenwünschen angepasst Antworten abzubilden müssten.

Jersey wirft einen com.sun.jersey.api.ParamException, wenn es um die Parameter entordnen nicht so eine Lösung ist eine ExceptionMapper zu schaffen, die diese Art von Ausnahmen behandelt:

@Provider
public class ParamExceptionMapper implements ExceptionMapper<ParamException> {
    @Override
    public Response toResponse(ParamException exception) {
        return Response.status(Status.BAD_REQUEST).entity(exception.getParameterName() + " incorrect type").build();
    }
}

Sie können auch eine wiederverwendbare Klasse für QueryParam-kommentierten Variablen

schreiben
public class DateParam {
  private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

  private Calendar date;

  public DateParam(String in) throws WebApplicationException {
    try {
      date = Calendar.getInstance();
      date.setTime(format.parse(in));
    }
    catch (ParseException exception) {
      throw new WebApplicationException(400);
    }
  }
  public Calendar getDate() {
    return date;
  }
  public String format() {
    return format.format(value.getTime());
  }
}

dann verwenden Sie es wie folgt aus:

private @QueryParam("from") DateParam startDateParam;
private @QueryParam("to") DateParam endDateParam;
// ...
startDateParam.getDate();

Obwohl die Fehlerbehandlung in diesem Fall (das Werfen eine 400-Antwort) trivial ist, die Verwendung dieser Klasse ermöglicht es Ihnen, Parameter Handhabung im Allgemeinen Faktor-out, welche enthalten können usw. anzumelden.

Eine offensichtliche Lösung: Nehmen Sie in einem String, wandeln sich auf dem Laufenden. So können Sie Format definieren können Sie, fangen Ausnahmen und entweder wieder Wurf oder anpassen Fehler wollen gesendet. Für die Analyse sollte Simple gut funktionieren.

Ich bin sicher, es gibt Möglichkeiten, auch Handler für Datentypen anschließen, aber vielleicht etwas einfacher Code ist alles, was Sie in diesem Fall benötigen.

ich auch wie StaxMan würde wahrscheinlich, dass QueryParam als String implementieren, dann die Umwandlung handhaben, Erneutes Auslösen wie nötig.

Wenn das Gebietsschema ein bestimmtes Verhalten ist die gewünschte und erwartete Verhalten, würden Sie die folgende verwenden, um die 400 Bad Request Fehler zurück:

throw new WebApplicationException(Response.Status.BAD_REQUEST);

Sehen Sie die JavaDoc javax.ws.rs.core.Response.Status für weitere Optionen.

@QueryParam Dokumentation sagt

  

“Der Typ T des kommentierten Parameter, Feld oder eine Eigenschaft muss   entweder:

     

1) eine primitive Art
  2) Haben Sie einen Konstruktor, der eine einzelne akzeptiert   String-Argument
  3) Haben Sie eine statische Methode namens valueOf oder vonString   dass akzeptiert ein einzelnes String-Argument (siehe zum Beispiel,   Integer.valueOf (String))
  4) eine eingetragene Umsetzung   javax.ws.rs.ext.ParamConverterProvider JAX-RS Erweiterung SPI dass   gibt eine Instanz von javax.ws.rs.ext.ParamConverter a „in der Lage aus   string“Konvertierung für den Typen.
  5) Seien Sie List, Set oder   SortedSet, wobei T 2 erfüllt, 3 oder 4 oben. die daraus resultierende   Sammlung ist schreibgeschützt. „

Wenn Sie möchten, steuern, welche als Reaktion auf Benutzer geht, wenn Abfrageparameter in String Form kann nicht in Ihrem Typ T umgewandelt werden, können Sie WebApplicationException werfen. Dropwizard kommt mit folgenden * Param Klassen, die Sie für Ihre Bedürfnisse nutzen können.

BooleanParam, DateTimeParam, intparam, LongParam, LocalDateParam, NonEmptyStringParam, UUIDParam. Siehe https: // github.com/dropwizard/dropwizard/tree/master/dropwizard-jersey/src/main/java/io/dropwizard/jersey/params

Wenn Sie Joda Datetime benötigen, verwenden Sie nur Dropwizard DateTimeParam .

Wenn die obige Liste nicht Ihren Anforderungen entspricht, definieren Sie Ihre eigenen durch AbstractParam erstreckt. Außer Kraft setzen Parse-Methode. Wenn Sie Fehlerreaktion Körper die Kontrolle über gekröpft Error-Methode.

Guter Artikel von Coda Hale auf diesem ist unter http: // codahale. com / was-macht-Jersey-interessant-Parameter-Klassen /

import io.dropwizard.jersey.params.AbstractParam;

import java.util.Date;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

public class DateParam extends AbstractParam<Date> {

    public DateParam(String input) {
        super(input);
    }

    @Override
    protected Date parse(String input) throws Exception {
        return new Date(input);
    }

    @Override
    protected Response error(String input, Exception e) {
        // customize response body if you like here by specifying entity
        return Response.status(Status.BAD_REQUEST).build();
    }
}

Datum (String arg) Konstruktor ist veraltet. Ich würde Java 8 Datum Klassen verwenden, wenn Sie auf Java sind 8. Ansonsten joda Datum Zeit empfohlen.

Dies ist das richtige Verhalten tatsächlich. Jersey wird versuchen, einen Handler für Ihre Eingabe zu finden und versuchen, ein Objekt aus der bereitgestellten Eingabe zu konstruieren. In diesem Fall wird es versuchen, ein neues Date-Objekt mit dem Wert X an den Konstruktor zur Verfügung gestellt zu erstellen. Da dies ein ungültiges Datum ist, durch Konvention wird Jersey 404. zurückkehren

Was Sie tun können, ist neu zu schreiben und das Geburtsdatum als String setzen, versuchen Sie dann zu analysieren, und wenn Sie nicht bekommen, was Sie wollen, sind Sie frei, jede Ausnahme werfen Sie durch eine der Ausnahme Abbildungsmechanismen wollen ( es gibt mehr).

So wie eine Erweiterung @ Steven Lavine Antwort, falls Sie den Browser Login-Fenster öffnen möchten. Ich fand es schwer, um richtig die Antwort zurück ( MDN HTTP-Authentifizierung ) aus dem Filter in dem Fall, dass der Benutzer noch nicht authentifiziert wurde

Das half mir die Antwort zu bauen, um Browser-Login zu erzwingen, beachten Sie die zusätzliche Modifikation der Header. Dadurch wird der Statuscode 401 einstellen und den Header gesetzt, der den Browser bewirkt, dass der Benutzername / Passwort-Dialog öffnen.

// The extended Exception class
public class NotLoggedInException extends WebApplicationException {
  public NotLoggedInException(String message) {
    super(Response.status(Response.Status.UNAUTHORIZED)
      .entity(message)
      .type(MediaType.TEXT_PLAIN)
      .header("WWW-Authenticate", "Basic realm=SecuredApp").build()); 
  }
}

// Usage in the Filter
if(headers.get("Authorization") == null) { throw new NotLoggedInException("Not logged in"); }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top