webentwicklung-frage-antwort-db.com.de

JSON aus RetrofitError-Objekt mit Retrofit abrufen

Ich benutze die Retrofit-Bibliothek, um REST zu einem Dienst aufzurufen, den ich benutze.

Wenn ich einen API-Aufruf an meinen Service durchführe und ein Fehler auftritt, gibt der Service ein bisschen JSON zusammen mit den Standard-HTTP-Fehlern zurück. Mit dem Objekt RetrofitError, das im Fehler-Rückruf enthalten ist, kann ich den HTTP-Statuscode und einige andere Dinge finden, jedoch nicht den JSON-Code abrufen, den der Dienst zurücksendet.

Angenommen, ich rufe die API auf, in der ich einen Benutzer erstellen möchte. Wenn der Benutzername bereits vorhanden ist, gibt der Service einen 400-Fehlercode zusammen mit JSON wie folgt zurück:

{"error":"Username already in use"}

Da ein einfacher 400-Fehlercode nicht spezifisch genug ist, muss ich auf den zurückgegebenen JSON-Code zugreifen können.

Weiß jemand, wie ich an diese JSON-Daten kommen kann? Ich habe versucht, jedes Feld im Objekt RetrofitError zu untersuchen und kann es nirgendwo finden. Muss ich noch etwas tun?

39
neonDion

Sie können die Methode getBodyAs des Objekts RetrofitError verwenden. Die Antwort wird ähnlich wie bei anderen Retrofit-Konvertierungen in ein Java) -Objekt konvertiert. Definieren Sie zunächst eine Klasse, die Ihre JSON-Fehlerantwort beschreibt:

class RestError {
    @SerializedName("code")
    public int code;
    @SerializedName("error")
    public String errorDetails;
}

Verwenden Sie dann die zuvor erwähnte Methode, um das Objekt abzurufen, das den Fehler ausführlicher beschreibt.

catch(RetrofitError error) {
    if (error.getResponse() != null) {
        RestError body = (RestError) error.getBodyAs(RestError.class);
        log(body.errorDetails);
        switch (body.code) {
            case 101:
                ...
            case 102:
                ...
        }
    }
}

Retrofit 2.0 hat die Art und Weise geändert, wie Fehlerreaktionen konvertiert werden. Sie müssen den richtigen Konverter mit der responseBodyConverter -Methode finden und ihn zum Konvertieren des Fehlerkörpers der Antwort verwenden. Mit Ausnahme der Ausnahmebehandlung wäre dies:

Converter<ResponseBody, RestError> converter 
    = retrofit.responseBodyConverter(RestError.class, new Annotation[0]);
RestError errorResponse = converter.convert(response.errorBody());
103
LukaCiko

Versuchen Sie diesen Code

@Override
public void failure(RetrofitError error) {
    String json =  new String(((TypedByteArray)error.getResponse().getBody()).getBytes());
    Log.v("failure", json.toString());
}

mit Retrofit 2.

@Override
public void onFailure(Call<Example> call, Throwable t) {
    String message = t.getMessage();
    Log.d("failure", message);
}
20
Cabezas

Two-Liner mit getBodyAs, um ein JSON-Objekt zu erhalten.

JsonObject responseAsJson = (JsonObject) retrofitError.getBodyAs(JsonElement.class);

String message = responseAsJson.get("error").getAsString(); //=> "Username already in use"

Bestätigt in Retrofit 1.x zu arbeiten. Nicht sicher, welche Änderungen für Retrofit 2.x erforderlich sind.

5
JaredBanyard

@ LukaCiko Antwort funktioniert jetzt nicht bei mir bei Retrofit 1.6.1. Hier wie ich es jetzt mache:

    @Override
    public void failure(RetrofitError retrofitError) {
        String json =  new String(((TypedByteArray)retrofitError.getResponse().getBody()).getBytes());
        //own logic for example
        ExampleHandlerError error = new Gson().fromJson(json, ExampleHandlerError.class);
    }
5
ar-g

Hiermit können Sie den Fehlerkörper erhalten

  if (response != null && response.errorBody() != null) {
    JSONObject jsonObject = new JSONObject(response.errorBody().string());
    String error =  jsonObject.getString("error");
  }
1
Amit Shekhar

Eine viel einfachere Möglichkeit, dies zu tun, besteht darin, eine Klasse zu erstellen, die das Parsing/die Konvertierung für Sie übernimmt und die Sie jederzeit und überall aufrufen können.

public class ApiError {
    public String error = "An error occurred";

    public ApiError(Throwable error) {
        if (error instanceof HttpException) {
            String errorJsonString = null;
            try {
                errorJsonString = ((HttpException) 
                error).response().errorBody().string();
            } catch (IOException e) {
                e.printStackTrace();
            }
            JsonElement parsedString = new 
            JsonParser().parse(errorJsonString);
            this.error = parsedString.getAsJsonObject()
                                     .get("error")
                                     .getAsString();
        } else {
            this.error = error.getMessage() != null ? error.getMessage() : this.error;
        }
    }
}

Sie können diese Funktion jetzt überall verwenden

ApiError error = new ApiError(error)
error.error

Dies ist alles von dieser Blog-Beitrag (den ich geschrieben habe).

1
Timi Ajiboye

Nach ein bisschen mehr Jagd fand ich die Antwort.

Hier ist mein Fehler-Rückruf:

@Override public void failure(RetrofitError retrofitError) {
    String serverError = null;
    try {
        serverError = extractServerError(retrofitError.getResponse().getBody().in());
    } catch (Exception e) {
        Log.e("LOG_TAG", "Error converting RetrofitError server JSON", e);
    }

    if (serverError!=null) {
        Log.i(LOG_TAG, serverError);
    }

    Intent intent = new Intent(ACTION_REGISTRATION_ERROR);
    intent.putExtra("ServerError", serverError);
    LocalBroadcastManager.getInstance(FamDooApplication.CONTEXT).sendBroadcastSync(intent);
}

Und hier ist die Methode, die aufgerufen wird, um den Serverfehler zu extrahieren:

public static String extractServerError(Java.io.InputStream is) {
    String serverError = null;
    String serverErrorDescription = null;
try {

    String s = convertStreamToString(is);

    JSONObject messageObject = new JSONObject(s);
    serverError = messageObject.optString("error");
    serverErrorDescription = messageObject.optString("error_description");
    if (serverErrorDescription!=null && !serverErrorDescription.equals("")) {
        return serverErrorDescription;
    } else {
        return serverError;
    }
    //String serverStack = messageObject.getString("stack");
} catch (Exception e) {
    Log.e("Basemodel", "Error converting RetrofitError server JSON", e);
}

return "";
}

Dadurch werden die Fehlerinformationen extrahiert, die vom in JSON codierten Service gesendet wurden.

0
neonDion

Ich kompiliere viele Antworten und schreibe Code, um etwas Schöneres zu erreichen:

{
    "errors": {
        "email": [
            "Email not valid.",
            "Unable to find the user [email protected]"
        ]
    }
}

Ich nehme alle Artikel in 'email' und zeige sie zusammen mit Guava Joiner an:

String json =  new String(((TypedByteArray)error.getResponse()
    .getBody()).getBytes());

Map<String, Object> map = new Gson().fromJson(
    json, new TypeToken<Map<String, Map<String, List<String>>>>() {}.getType());

try {
    List<String> errorsEmail = 
        (List<String>) ((Map)map.get("errors")).get("email");
    Toast.makeText(getApplicationContext(), Joiner.on("\n")
        .join(errorsEmail), Toast.LENGTH_SHORT).show();
} catch(Exception e){
    Log.e(Constants.TAG, e.getMessage());
}
0
Hugo Gresse

Ich hatte das gleiche. Mein Problem war ein long Feld, das vom Server als leeres String"". Retrofit gab NumberFormatException, weil es so aussieht, als würde Gson keine leere Zeichenkette in long konvertieren (ich würde vorschlagen, sie auf 0L oder so zu setzen). Also musste ich wechseln:

long errorCode;

zu

String errorCode;

Wie bereits gesagt, hatte ich beim Debuggen keinen Zugriff auf die JSON-Nachricht. Endlich habe ich den Fehler auf der RequestMaker-Seite gefunden. Vielleicht hilft er jemand anderem

http://requestmaker.com/

0
voghDev