2.0 कैसे deserialised त्रुटि प्रतिक्रिया पाने के लिए


128

मैं Retrofit 2.0.0-beta1 का उपयोग कर रहा हूं ।

परीक्षणों में मैं एक वैकल्पिक परिदृश्य है और त्रुटि HTTP 400 की उम्मीद है

मैं चाहूंगा retrofit.Response<MyError> response लेकिनresponse.body() == null

MyError deserialised नहीं है - मैं इसे केवल यहां देखता हूं

response.errorBody().string()

लेकिन यह मुझे ऑब्जेक्ट के रूप में MyError नहीं देता है



क्या यह त्रुटि प्रतिक्रिया का वर्णन करने के लिए एक अच्छा अभ्यास है? चूंकि प्रतिक्रिया एक वेबसर्वर त्रुटि हो सकती है जो html है।
होसैन शाहदोस्त

1
thx @ahmadalibaloch, यह लिंक वास्तव में बहुत उपयोगी है।
रवि वानिया

जवाबों:


138

मैं वर्तमान में बहुत आसान कार्यान्वयन का उपयोग करता हूं, जिसके लिए कन्वर्टर्स या विशेष वर्गों का उपयोग करने की आवश्यकता नहीं है। मेरे द्वारा उपयोग किया जाने वाला कोड निम्नलिखित है:

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();
        }
    }
}

6
आपका समाधान त्रुटि प्रतिक्रिया सामग्री नहीं दिखाता है।
कूलमाइंड

1
मेरे संपादन की जाँच करें, पता नहीं क्यों मैंने इसे पहली जगह में इतना अस्पष्ट बना दिया।
सैफ बेचन

4
अंत में, एंड्रॉइड प्रश्न का एक सरल उत्तर जो काम करता है (अधिकांश एंड्रॉइड उत्तर कॉमिक रूप से जटिल हैं)।
डग वॉस

यह निश्चित रूप से सवाल का जवाब नहीं दे रहा है। यह केवल त्रुटि संदेश लौटाता है न कि एरर एनम ऑब्जेक्ट। कृपया इस प्रतिक्रिया का अनुसरण करें: stackoverflow.com/a/21103420/2914140
तोबलीगूग

जवाब में यह "संदेश" के लिए मैपिंग की तलाश में है, लेकिन मेरी त्रुटि प्रतिक्रिया में ऐसा नहीं था। इसमें "त्रुटि" के लिए मैपिंग थी। तो हर कोई पढ़ रहा है, यह आपको मिलने वाली प्रतिक्रिया पर निर्भर करता है!
mco

43

ErrorResponse आपकी कस्टम प्रतिक्रिया वस्तु है

Kotlin

val gson = Gson()
val type = object : TypeToken<ErrorResponse>() {}.type
var errorResponse: ErrorResponse? = gson.fromJson(response.errorBody()!!.charStream(), type)

जावा

Gson gson = new Gson();
Type type = new TypeToken<ErrorResponse>() {}.getType();
ErrorResponse errorResponse = gson.fromJson(response.errorBody.charStream(),type);

3
आपको gson.fromJson(response.errorBody()?.charStream(), type)
अल्टरनेटिंग ऑप्शंस को

37

मैंने इसे हल किया:

 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 क्लास:

  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;
     }
   }

2
java.lang.IllegalStateException: BEGIN_OBJECT की अपेक्षा की गई थी, लेकिन लाइन 1 कॉलम 2 पथ $ पर
रो रही

.addConverterFactory(ScalarsConverterFactory.create())@RonelGonzales का उपयोग करें
प्रतीक बुटानी

30

रेट्रोफिट 2.0 बीटा 2 में यह तरीका है कि मुझे त्रुटि प्रतिक्रियाएं मिल रही हैं:

  1. एक समय का

    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
    }
  2. अतुल्यकालिक

    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
        }
    });

रेट्रोफ़िट 2 बीटा 3 के लिए अपडेट:

  1. समकालिक - परिवर्तित नहीं
  2. एसिंक्रोनस - रेट्रोफिट पैरामीटर को ऑनरस्पॉन्ड से हटा दिया गया था

    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
        }
    });

4
आपके पास BasicResponse में क्या है?
जेमशीट इस्केंडरोव

2
बस एक मूल जैक्सन एनोटेट वर्ग जिसमें संदेश और त्रुटि कोड होता है। किसी भी स्थिति में आपके पास कोई भी एनोटेट वर्ग हो सकता है जो आपके सर्वर प्रतिक्रिया प्रकार से मेल खाता हो। अपनी आवश्यकताओं के मिलान के लिए jsonschema2pojo का उपयोग करने का प्रयास करें ।
JFreeman

दूसरों के लिए, आप इसके बजाय इसका उपयोग कर सकते हैं: कन्वर्टर <ResponseBody, <Message> errorConverter = retrofit.responseBodyConverter (Message.class, new Annotation [0]);
किम मोंटानो

@JFreeman, क्या होगा अगर मैं deserialize करना चाहता हूं List<BasicResponse>?
अज़ीज़बेकियन

क्या आप मेरे लिए कक्षा MyApplication
dungtv

10

में https://stackoverflow.com/a/21103420/2914140 और https://futurestud.io/tutorials/retrofit-2-simple-error-handling इस प्रकार रेट्रोफिट 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();
            }
        }
    }

9
 @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();
                }

            }

9

प्रतिक्रिया को बदलने के लिए त्रुटि प्रतिक्रिया और उपयोगकर्ता Gson का एक मॉडल बनाएं। यह सिर्फ ठीक काम करेगा।

APIError.java

public class APIError {
    private String message;

    public String getMessage() {
        return message;
    }
}

MainActivity.java (अंदर अनुरोध पर)

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();
}

7

मैंने इसे रिट्रोफिट 2.0-बीटा 2 का उपयोग करते हुए अतुल्यकालिक कॉल के लिए किया था:

@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();
        }
    }
}

MyError वर्ग क्या होगा?
ध्रुपाल

मैंने सोचा था कि ऑनरस्पॉन्स में कॉल पैरामीटर और रिस्पॉन्स पैरामीटर होना चाहिए था। यह कैसे है कि तुम्हारा एक रेट्रोफिट पैरामीटर है?
मार्टी मिलर

@MartyMiller यह रेट्रोफिट 2.0-बीटा
शांतनु

7

यदि आप कोटलिन का उपयोग करते हैं तो एक अन्य समाधान प्रतिक्रिया वर्ग के लिए विस्तार फ़ंक्शन बना सकता है:

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
}

प्रयोग

val myError = response.parseErrJsonResponse<MyErrorResponse>()
if(myError != null) {
   // handle your error logic here
   // ...
}

अंत में किसी ने कोडलाइन पावर का उपयोग कोड को पढ़ने में आसान बनाने के लिए किया!
विंस

6

यह वास्तव में बहुत सीधा है।

Kotlin:

val jsonObj = JSONObject(response.errorBody()!!.charStream().readText())
responseInterface.onFailure(jsonObj.getString("msg"))

जावा:

JSONObject jsonObj = new JSONObject(response.errorBody().charStream().readText());
responseInterface.onFailure(jsonObj.getString("msg"));

रेट्रोफिट पर परीक्षण किया गया: 2.5.0। टेक्स्ट को चारस्ट्रीम से पढ़ें जो आपको एक स्ट्रिंग देगा, फिर JSONObject पर पार्स करें।

Adios।


readText()जावा पर कोई विस्तार नहीं है , TextStreamsKt.readText(response.errorBody().charStream())यदि आप अभी भी जावा पर उपयोग करते हैं
मोचडवी

4

मैं उसी मुद्दे का सामना कर रहा था। मैंने इसे रेट्रोफिट के साथ हल किया। मुझे यह दिखाने दो ...

यदि आपकी त्रुटि JSON संरचना की तरह है

{
"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;
   }
}

और यह मेरी त्रुटि स्थिति वर्ग है

public class ErrorStatus {

  @SerializedName("status")
  @Expose
  private String status;

  public String getStatus() {
      return status;
  }

  public void setStatus(String status) {
      this.status = status;
  }
}

अब हमें एक ऐसे वर्ग की जरूरत है जो हमारे जज्बे को संभाल सके।

  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;
}
}

अब हम रेट्रोफिट एपि कॉल में अपनी प्रतिक्रिया की जांच कर सकते हैं

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) {

        }
    });
}

यही अब आप अपना टोस्ट दिखा सकते हैं


4

Kotlinएक्सटेंशन का उपयोग करके यहां सुरुचिपूर्ण समाधान दिया गया है :

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
}

और उपयोग:

showError(retrofitThrowable.getApiError()?.message)


3

इस तरह से आपको किसी रेट्रोफिट उदाहरण की आवश्यकता नहीं है यदि आप केवल रेट्रोफिट से बनाई गई सेवा को इंजेक्ट कर रहे हैं।

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;
  }
}

इसे इस तरह उपयोग करें:

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();
    }
  }

2

यह समस्या तब लगती है जब आप रेट्रोफिट के साथ-साथ OkHttp का उपयोग करते हैं, इसलिए या तो आप OkHttp को हटा सकते हैं या त्रुटि बॉडी प्राप्त करने के लिए नीचे दिए गए कोड का उपयोग कर सकते हैं:

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(); 
}
}

2

त्रुटि पढ़ें स्ट्रिंग के लिए और मैन्युअल रूप से पार्स जोंस।

 if(!response.isSuccessful()) {
   
    String error = "";
    try {
        BufferedReader ereader = new BufferedReader(new InputStreamReader(
                response.errorBody().byteStream()));
        String eline = null;
        while ((eline = ereader.readLine()) != null) {
            error += eline + "";
        }
        ereader.close();
    } catch (Exception e) {
        error += e.getMessage();
    }
    Log.e("Error",error);
    
    try {
        JSONObject reader = new JSONObject(error);
        String message = reader.getString("message");
    
        Toast.makeText(context,message,Toast.LENGTH_SHORT).show();
    
    } catch (JSONException e) {
        e.printStackTrace();
    }
 }

0

इसे हल किया:

Converter<MyError> converter = 
    (Converter<MyError>)JacksonConverterFactory.create().get(MyError.class);
MyError myError =  converter.fromBody(response.errorBody());

मैं GsonConverterFactory के माध्यम से कैसे परिवर्तित कर सकता हूं? कोई उपाय ?
शान ज़ीशी

मुझे एक रास्ता मिल गया है। मैं सिर्फ इसे बदल देता हूं, यह मेरे कस्टम ऑब्जेक्ट में JacksonConverterFactory GsonConverterFactory
जोंस

3
MyError वर्ग के पास क्या है?
ध्रुपाल

0
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();
            }

0

कोटलिन में:

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) {
    }
})

0

त्रुटिबॉडी मानों को रेट्रोफिट में APIError ऑब्जेक्ट सेट करना चाहिए। ताकि, आप नीचे दिए गए कोड संरचना का उपयोग कर सकें।

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) {
    ....
}

0

परीक्षण किया और काम करता है

 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;
        }

-1
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)`
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.