Ik gebruik Retrofit 2.0.0-beta1.
Tijdens tests heb ik een alternatief scenario en verwacht ik fout HTTP 400
Ik wil graag retrofit.Response<MyError> response
maar response.body() == null
MyError is niet gedeserialiseerd – ik zie het alleen hier
response.errorBody().string()
maar ik krijg MyError niet als object
Antwoord 1, autoriteit 100%
Ik gebruik momenteel een zeer eenvoudige implementatie, waarvoor geen converters of speciale klassen nodig zijn. De code die ik gebruik is de volgende:
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
DialogHelper.dismiss();
if (response.isSuccessful()) {
// Do your success stuff...
} else {
try {
JSONObject jObjError = new JSONObject(response.errorBody().string());
Toast.makeText(getContext(), jObjError.getJSONObject("error").getString("message"), Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
Een punt om op te merken is dat response.errorBody().string()
slechts één keer de juiste waarde zal retourneren. Als u het opnieuw aanroept, wordt een lege tekenreeks geretourneerd. Dus als je het opnieuw wilt gebruiken, sla de waarde dan op in een variabele bij de eerste aanroep.
Antwoord 2, autoriteit 42%
ErrorResponseis uw aangepaste responsobject
Kotlin
val gson = Gson()
val type = object : TypeToken<ErrorResponse>() {}.type
var errorResponse: ErrorResponse? = gson.fromJson(response.errorBody()!!.charStream(), type)
Java
Gson gson = new Gson();
Type type = new TypeToken<ErrorResponse>() {}.getType();
ErrorResponse errorResponse = gson.fromJson(response.errorBody.charStream(),type);
Antwoord 3, autoriteit 24%
Ik heb het opgelost door:
if(!response.isSuccessful()){
Gson gson = new Gson();
MyErrorMessage message=gson.fromJson(response.errorBody().charStream(),MyErrorMessage.class);
if(message.getCode()==ErrorCode.DUPLICATE_EMAIL_ID_CODE){
//DO Error Code specific handling
}else{
//DO GENERAL Error Code Specific handling
}
}
MyErrorMessage-klasse:
public class MyErrorMessage {
private int code;
private String message;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Antwoord 4, autoriteit 17%
In Retrofit 2.0 beta2 krijg ik op deze manier foutmeldingen:
-
Synchroon
try { Call<RegistrationResponse> call = backendServiceApi.register(data.in.account, data.in.password, data.in.email); Response<RegistrationResponse> response = call.execute(); if (response != null && !response.isSuccess() && response.errorBody() != null) { Converter<ResponseBody, BasicResponse> errorConverter = MyApplication.getRestClient().getRetrofitInstance().responseConverter(BasicResponse.class, new Annotation[0]); BasicResponse error = errorConverter.convert(response.errorBody()); //DO ERROR HANDLING HERE return; } RegistrationResponse registrationResponse = response.body(); //DO SUCCESS HANDLING HERE } catch (IOException e) { //DO NETWORK ERROR HANDLING HERE }
-
Asynchroon
Call<BasicResponse> call = service.loadRepo(); call.enqueue(new Callback<BasicResponse>() { @Override public void onResponse(Response<BasicResponse> response, Retrofit retrofit) { if (response != null && !response.isSuccess() && response.errorBody() != null) { Converter<ResponseBody, BasicResponse> errorConverter = retrofit.responseConverter(BasicResponse.class, new Annotation[0]); BasicResponse error = errorConverter.convert(response.errorBody()); //DO ERROR HANDLING HERE return; } RegistrationResponse registrationResponse = response.body(); //DO SUCCESS HANDLING HERE } @Override public void onFailure(Throwable t) { //DO NETWORK ERROR HANDLING HERE } });
Update voor Retrofit 2 beta3:
- Synchroon – niet gewijzigd
-
Asynchroon – Retrofit-parameter is verwijderd uit onResponse
Call<BasicResponse> call = service.loadRepo(); call.enqueue(new Callback<BasicResponse>() { @Override public void onResponse(Response<BasicResponse> response) { if (response != null && !response.isSuccess() && response.errorBody() != null) { Converter<ResponseBody, BasicResponse> errorConverter = MyApplication.getRestClient().getRetrofitInstance().responseConverter(BasicResponse.class, new Annotation[0]); BasicResponse error = errorConverter.convert(response.errorBody()); //DO ERROR HANDLING HERE return; } RegistrationResponse registrationResponse = response.body(); //DO SUCCESS HANDLING HERE } @Override public void onFailure(Throwable t) { //DO NETWORK ERROR HANDLING HERE } });
Antwoord 5, autoriteit 17%
Het is eigenlijk heel eenvoudig.
Kotlin:
val jsonObj = JSONObject(response.errorBody()!!.charStream().readText())
responseInterface.onFailure(jsonObj.getString("msg"))
Java:
if(response.errorBody()!=null){
JSONObject jsonObj = new JSONObject(TextStreamsKt.readText(response.errorBody().charStream()));
responseInterface.onFailure(jsonObj.getString("msg"));
}else{
responseInterface.onFailure("you might want to return a generic error message.");
}
Getest bij retrofit: 2.5.0.
Lees de tekst van de charStream die je een String geeft en ontleden vervolgens naar JSONObject.
Adios.
Antwoord 6, autoriteit 14%
Maak een model van de foutreactie & gebruiker Gson om het antwoord ernaar te converteren. Dit werkt prima.
APIERror.java
public class APIError {
private String message;
public String getMessage() {
return message;
}
}
MainActivity.java(binnen verzoek onResponse)
if (response.isSuccessful()) {
// Do your success stuff...
} else {
APIError message = new Gson().fromJson(response.errorBody().charStream(), APIError.class);
Toast.makeText(MainActivity.this, "" + message.getMessage(), Toast.LENGTH_SHORT).show();
}
Antwoord 7, autoriteit 6%
@Override
public void onResponse(Call<Void> call, retrofit2.Response<Void> response) {
if (response.isSuccessful()) {
//Do something if response is ok
} else {
JsonParser parser = new JsonParser();
JsonElement mJson = null;
try {
mJson = parser.parse(response.errorBody().string());
Gson gson = new Gson();
MyError errorResponse = gson.fromJson(mJson, MyError.class);
} catch (IOException ex) {
ex.printStackTrace();
}
}
Antwoord 8, autoriteit 6%
In https://stackoverflow.com/a/21103420/2914140en https://futurestud.io/tutorials/retrofit-2-simple-error-handlingdeze variant wordt getoond voor Retrofit 2.1.0.
call.enqueue(new Callback<MyResponse>() {
@Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
if (response.isSuccessful()) {
...
} else {
Converter<ResponseBody, MyError> converter
= MyApplication.getRetrofit().responseBodyConverter(
MyError.class, new Annotation[0]);
MyError errorResponse = null;
try {
errorResponse = converter.convert(response.errorBody());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Antwoord 9, autoriteit 4%
Als je Kotlin gebruikt, kan een andere oplossing zijn om gewoon een extensiefunctie voor de Response-klasse te maken:
inline fun <reified T>Response<*>.parseErrJsonResponse(): T?
{
val moshi = MyCustomMoshiBuilder().build()
val parser = moshi.adapter(T::class.java)
val response = errorBody()?.string()
if(response != null)
try {
return parser.fromJson(response)
} catch(e: JsonDataException) {
e.printStackTrace()
}
return null
}
Gebruik
val myError = response.parseErrJsonResponse<MyErrorResponse>()
if(myError != null) {
// handle your error logic here
// ...
}
Antwoord 10, autoriteit 3%
Ik deed het op deze manier voor asynchrone oproepen met Retrofit 2.0-beta2:
@Override
public void onResponse(Response<RegistrationResponse> response,
Retrofit retrofit) {
if (response.isSuccess()) {
// Do success handling here
} else {
try {
MyError myError = (MyError)retrofit.responseConverter(
MyError.class, MyError.class.getAnnotations())
.convert(response.errorBody());
// Do error handling here
} catch (IOException e) {
e.printStackTrace();
}
}
}
Antwoord 11, autoriteit 3%
Ik had hetzelfde probleem. Ik heb het opgelost met retrofit. Laat me dit laten zien…
Als uw fout JSON-structuur is zoals
{
"error": {
"status": "The email field is required."
}
}
My ErrorRespnce.java
public class ErrorResponse {
@SerializedName("error")
@Expose
private ErrorStatus error;
public ErrorStatus getError() {
return error;
}
public void setError(ErrorStatus error) {
this.error = error;
}
}
En dit is mijn foutstatusklasse
public class ErrorStatus {
@SerializedName("status")
@Expose
private String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
Nu hebben we een klasse nodig die onze json aankan.
public class ErrorUtils {
public static ErrorResponse parseError (Response<?> response){
Converter<ResponseBody , ErrorResponse> converter = ApiClient.getClient().responseBodyConverter(ErrorResponse.class , new Annotation[0]);
ErrorResponse errorResponse;
try{
errorResponse = converter.convert(response.errorBody());
}catch (IOException e){
return new ErrorResponse();
}
return errorResponse;
}
}
Nu kunnen we onze reactie controleren in de retrofit API-aanroep
private void registrationRequest(String name , String email , String password , String c_password){
final Call<RegistrationResponce> registrationResponceCall = apiInterface.getRegistration(name , email , password , c_password);
registrationResponceCall.enqueue(new Callback<RegistrationResponce>() {
@Override
public void onResponse(Call<RegistrationResponce> call, Response<RegistrationResponce> response) {
if (response.code() == 200){
}else if (response.code() == 401){
ErrorResponse errorResponse = ErrorUtils.parseError(response);
Toast.makeText(MainActivity.this, ""+errorResponse.getError().getStatus(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<RegistrationResponce> call, Throwable t) {
}
});
}
Dat is het, nu kun je je Toast laten zien
Antwoord 12, autoriteit 3%
Hier is een elegante oplossing met behulp van Kotlin
-extensies:
data class ApiError(val code: Int, val message: String?) {
companion object {
val EMPTY_API_ERROR = ApiError(-1, null)
}
}
fun Throwable.getApiError(): ApiError? {
if (this is HttpException) {
try {
val errorJsonString = this.response()?.errorBody()?.string()
return Gson().fromJson(errorJsonString, ApiError::class.java)
} catch (exception: Exception) {
// Ignore
}
}
return EMPTY_API_ERROR
}
en gebruik:
showError(retrofitThrowable.getApiError()?.message)
Antwoord 13, autoriteit 3%
if(!response.isSuccessful()) {
StringBuilder error = new StringBuilder();
try {
BufferedReader bufferedReader = null;
if (response.errorBody() != null) {
bufferedReader = new BufferedReader(new InputStreamReader(
response.errorBody().byteStream()));
String eLine = null;
while ((eLine = bufferedReader.readLine()) != null) {
error.append(eLine);
}
bufferedReader.close();
}
} catch (Exception e) {
error.append(e.getMessage());
}
Log.e("Error", error.toString());
}
Antwoord 14, autoriteit 2%
Op deze manier heeft u geen Retrofit-instantie nodig als u alleen een service injecteert die is gemaakt met Retrofit.
public class ErrorUtils {
public static APIError parseError(Context context, Response<?> response) {
APIError error = new APIError();
try {
Gson gson = new Gson();
error = gson.fromJson(response.errorBody().charStream(), APIError.class);
} catch (Exception e) {
Toast.makeText(context, e.getMessage(), Toast.LENGTH_LONG).show();
}
if (TextUtils.isEmpty(error.getErrorMessage())) {
error.setError(response.raw().message());
}
return error;
}
}
Gebruik het als volgt:
if (response.isSuccessful()) {
...
} else {
String msg = ErrorUtils.parseError(fragment.getActivity(), response).getError(); // would be from your error class
Snackbar.make(someview, msg, Snackbar.LENGTH_LONG).show();
}
}
Antwoord 15
Dit lijkt het probleem te zijn wanneer u OkHttp samen met Retrofit gebruikt, dus u kunt OkHttp verwijderen of onderstaande code gebruiken om de hoofdtekst van de fout te krijgen:
if (!response.isSuccessful()) {
InputStream i = response.errorBody().byteStream();
BufferedReader r = new BufferedReader(new InputStreamReader(i));
StringBuilder errorResult = new StringBuilder();
String line;
try {
while ((line = r.readLine()) != null) {
errorResult.append(line).append('\n');
}
} catch (IOException e) {
e.printStackTrace();
}
}
Antwoord 16
Er zijn al veel geldige antwoorden. Dit is slechts een toevoeging voor een gebruikssituatie, wanneer u dezelfde Retrofit-reactie meer dan eens moet gebruiken. Geen van beide kan worden gebruikt, zoals u kunt de hoofdtekst van de reactie maar één keer lezen, omdat deze daarna wordt gesloten en u elke volgende keer null
krijgt, wanneer u probeert te lezen van hetzelfde antwoordobject:
response()?.errorBody()?.charStream()?.readText()
response()?.errorBody()?.string()
In plaats daarvan kunt u een alleen-lezen kopie van de antwoordreeks krijgen (terwijl de reactie zelf kan worden doorgegeven en uiteindelijk later kan worden gebruikt):
response()?.errorBody()?.source()?.buffer?.snapshot()?.utf8()
Antwoord 17
opgelost door:
Converter<MyError> converter =
(Converter<MyError>)JacksonConverterFactory.create().get(MyError.class);
MyError myError = converter.fromBody(response.errorBody());
Antwoord 18
try{
ResponseBody response = ((HttpException) t).response().errorBody();
JSONObject json = new JSONObject( new String(response.bytes()) );
errMsg = json.getString("message");
}catch(JSONException e){
return t.getMessage();
}
catch(IOException e){
return t.getMessage();
}
Antwoord 19
In Kotlin:
val call = APIClient.getInstance().signIn(AuthRequestWrapper(AuthRequest("1234567890z", "12341234", "nonce")))
call.enqueue(object : Callback<AuthResponse> {
override fun onResponse(call: Call<AuthResponse>, response: Response<AuthResponse>) {
if (response.isSuccessful) {
} else {
val a = object : Annotation{}
val errorConverter = RentalGeekClient.getRetrofitInstance().responseBodyConverter<AuthFailureResponse>(AuthFailureResponse::class.java, arrayOf(a))
val authFailureResponse = errorConverter.convert(response.errorBody())
}
}
override fun onFailure(call: Call<AuthResponse>, t: Throwable) {
}
})
Antwoord 20
errorBody-waarden moeten het APIError-object in Retrofit instellen. Zodat u de onderstaande codestructuur kunt gebruiken.
public class APIErrorUtils {
public static APIError parseError(Response<?> response) {
Converter<ResponseBody, APIError> converter = API.getClient().responseBodyConverter(APIError.class, new Annotation[0]);
APIError error;
try {
error = converter.convert(response.errorBody());
Log.d("SERVICELOG", "****************************************************");
Log.d("SERVICELOG", "***** SERVICE LOG");
Log.d("SERVICELOG", "***** TIMESTAMP: " + String.valueOf(error.getTimestamp()));
Log.d("SERVICELOG", "***** STATUS: " + String.valueOf(error.getStatus()));
Log.d("SERVICELOG", "***** ERROR: " + error.getError());
Log.d("SERVICELOG", "***** MESSAGE: " + error.getMessage());
Log.d("SERVICELOG", "***** PATH: " + error.getPath());
Log.d("SERVICELOG", "****************************************************");
} catch (IOException e) {
return new APIError();
}
return error;
}
}
APIError error = APIErrorUtils.parseError(response);
if (error.getStatus() == 400) {
....
}
Antwoord 21
Getest en werkt
public BaseModel parse(Response<BaseModel> response , Retrofit retrofit){
BaseModel error = null;
Converter<ResponseBody, BaseModel> errorConverter =
retrofit.responseBodyConverter(BaseModel.class, new Annotation[0]);
try {
if (response.errorBody() != null) {
error = errorConverter.convert(response.errorBody());
}
} catch (IOException e) {
e.printStackTrace();
}
return error;
}
Antwoord 22
val error = JSONObject(callApi.errorBody()?.string() as String)
CustomResult.OnError(CustomNotFoundError(userMessage = error["userMessage"] as String))
open class CustomError (
val traceId: String? = null,
val errorCode: String? = null,
val systemMessage: String? = null,
val userMessage: String? = null,
val cause: Throwable? = null
)
open class ErrorThrowable(
private val traceId: String? = null,
private val errorCode: String? = null,
private val systemMessage: String? = null,
private val userMessage: String? = null,
override val cause: Throwable? = null
) : Throwable(userMessage, cause) {
fun toError(): CustomError = CustomError(traceId, errorCode, systemMessage, userMessage, cause)
}
class NetworkError(traceId: String? = null, errorCode: String? = null, systemMessage: String? = null, userMessage: String? = null, cause: Throwable? = null):
CustomError(traceId, errorCode, systemMessage, userMessage?: "Usted no tiene conexión a internet, active los datos", cause)
class HttpError(traceId: String? = null, errorCode: String? = null, systemMessage: String? = null, userMessage: String? = null, cause: Throwable? = null):
CustomError(traceId, errorCode, systemMessage, userMessage, cause)
class UnknownError(traceId: String? = null, errorCode: String? = null, systemMessage: String? = null, userMessage: String? = null, cause: Throwable? = null):
CustomError(traceId, errorCode, systemMessage, userMessage?: "Unknown error", cause)
class CustomNotFoundError(traceId: String? = null, errorCode: String? = null, systemMessage: String? = null, userMessage: String? = null, cause: Throwable? = null):
CustomError(traceId, errorCode, systemMessage, userMessage?: "Data not found", cause)`
Antwoord 23
Fout bij verwerking van carrosserie in kotlin Android
catch (cause: Throwable) {
when (cause) {
is HttpException -> {
try {
val YourErrorResponseClassObj = Gson().fromJson(cause.response()?.errorBody()?.charStream(), YourErrorResponseClass::class.java)
} catch (e: Exception) {
}
}
else -> {
//Other errors like Network ...
}
}
}
Antwoord 24
heel eenvoudig. en dit redt mijn leven ooit
public static void displayApiResponseErrorBody(Response<?> response)
{
InputStream i = response.errorBody().byteStream();
BufferedReader r = new BufferedReader(new InputStreamReader(i));
StringBuilder errorResult = new StringBuilder();
String line;
try {
while ((line = r.readLine()) != null)
{
errorResult.append(line).append('\n');
}
Log.d("API_RESPONSE_ERROR_BODY",String.valueOf(errorResult));
System.out.println(errorResult);
} catch (IOException e) {
e.printStackTrace();
}
}