รับรหัสสถานะการตอบกลับโดยใช้ Retrofit 2.0 และ RxJava


111

ฉันกำลังพยายามอัปเกรดเป็น Retrofit 2.0 และเพิ่ม RxJava ในโปรเจ็กต์ Android ของฉัน ฉันกำลังทำการเรียก API และต้องการดึงรหัสข้อผิดพลาดในกรณีที่มีการตอบสนองข้อผิดพลาดจากเซิร์ฟเวอร์

Observable<MyResponseObject> apiCall(@Body body);

และในการเรียก RxJava:

myRetrofitObject.apiCall(body).subscribe(new Subscriber<MyResponseObject>() {
        @Override
        public void onCompleted() {

        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onNext(MyResponseObject myResponseObject) {
           //On response from server
        }
    });

ใน Retrofit 1.9 RetrofitError ยังคงมีอยู่และเราสามารถรับสถานะได้โดยทำ:

error.getResponse().getStatus()

คุณทำสิ่งนี้กับ Retrofit 2.0 โดยใช้ RxJava ได้อย่างไร?

คำตอบ:


187

แทนที่จะประกาศการเรียก API เหมือนที่คุณทำ:

Observable<MyResponseObject> apiCall(@Body body);

คุณยังสามารถประกาศได้ดังนี้:

Observable<Response<MyResponseObject>> apiCall(@Body body);

จากนั้นคุณจะมีสมาชิกดังต่อไปนี้:

new Subscriber<Response<StartupResponse>>() {
    @Override
    public void onCompleted() {}

    @Override
    public void onError(Throwable e) {
        Timber.e(e, "onError: %", e.toString());

        // network errors, e. g. UnknownHostException, will end up here
    }

    @Override
    public void onNext(Response<StartupResponse> startupResponseResponse) {
        Timber.d("onNext: %s", startupResponseResponse.code());

        // HTTP errors, e. g. 404, will end up here!
    }
}

ดังนั้นการตอบสนองของเซิร์ฟเวอร์ที่มีรหัสข้อผิดพลาดก็จะถูกส่งไปยังและคุณจะได้รับรหัสโดยการเรียกonNextreponse.code()

http://square.github.io/retrofit/2.x/retrofit/retrofit/Response.html

แก้ไข:ตกลงในที่สุดฉันก็มองไปรอบ ๆ เพื่อเป็นสิ่งที่ E-Nouri กล่าวว่าในความคิดเห็นของพวกเขาคือว่ามีเพียง 2xx onNextรหัสเพื่อจะไป ปรากฎว่าเราถูกต้องทั้งคู่:

หากมีการประกาศการโทรเช่นนี้:

Observable<Response<MyResponseObject>> apiCall(@Body body);

หรือแม้แต่สิ่งนี้

Observable<Response<ResponseBody>> apiCall(@Body body);

คำตอบทั้งหมดจะลงเอยด้วยonNextไม่ว่าจะเป็นรหัสข้อผิดพลาดใดก็ตาม สิ่งนี้เป็นไปได้เพราะทุกอย่างถูกห่อหุ้มด้วยResponseวัตถุโดย Retrofit

ในทางกลับกันหากมีการประกาศการโทรเช่นนี้:

Observable<MyResponseObject> apiCall(@Body body);

หรือนี่

Observable<ResponseBody> apiCall(@Body body);

จะมีเพียงการตอบกลับ 2xx onNextเท่านั้น ทุกสิ่งทุกอย่างจะถูกห่อในและส่งไปยังHttpException onErrorซึ่งก็สมเหตุสมผลเช่นกันเพราะหากไม่มีResponseกระดาษห่อหุ้มสิ่งที่ควรปล่อยออกมาonNext? เนื่องจากคำขอไม่ประสบความสำเร็จสิ่งเดียวที่จะเปล่งออกมาคือnull...


17
สำหรับผู้ที่กำลังมองหารหัส HTTP 4xx จะลงเอยด้วย HttpException ใน onError onNext จะมี 2xx เท่านั้น
e-nouri

2
น่าสนใจ ... ฉันเพิ่งตรวจสอบอีกครั้ง ( gist.github.com/DavidMihola/17a6ea373b9312fb723b ) และรหัสทั้งหมดที่ฉันลองลงท้ายด้วยonNext404 เป็นต้นฉันใช้ Retrofit v2.0.0-beta3
david.mihola

@ e-nouri: ฉันเพิ่งเพิ่มย่อหน้าในคำตอบที่คำนึงถึงความคิดเห็นของคุณ!
david.mihola

1
@ david.mihola ถ้า Build Retrofit ผ่าน add GsonConverterFactoryเหมือนกับRetrofit retrofit = new Retrofit.Builder() .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create())จะได้รับการตอบกลับแบบเดิมได้อย่างไร?
Honghe.Wu

1
นอกเหนือจากการจัดการข้อผิดพลาดฉันคิดว่าคุณอาจต้องการตรวจสอบส่วนหัวการตอบสนองใด ๆ ที่มาพร้อมกับเนื้อหาซึ่งเป็นไปได้ก็ต่อเมื่อคุณได้รับไฟล์Response. ฉันไม่ค่อยได้ใช้มันด้วย - แต่ฉันคิดว่ามันเป็นเรื่องดีที่รู้ว่ามันมีอยู่จริง
david.mihola

112

วิธีการ onError ภายในใส่สิ่งนี้เพื่อรับรหัส

((HttpException) e).code()

7
นี่อาจเป็นหนึ่งในคำตอบที่ประเมินต่ำที่สุดที่ฉันเคยเห็นใน SO นี่คืออัจฉริยะ คุณสามารถทำทุกอย่างที่จำเป็นเพื่อตอบสนองHttpExceptionได้ ฉันใช้ RxJava และฉันต้องการแยกวิเคราะห์การตอบสนองหลังจากได้รับไฟล์HTTP 400 BAD REQUEST. ขอบคุณมาก!
GabrielOshiro

29
ตรวจสอบให้แน่ใจว่าเป็นอินสแตนซ์ของ HttpException ก่อนหรือไม่เนื่องจาก NetworkErrors จะเป็น IOExceptions และไม่มีรหัสสถานะ
Benjamin Mesing

หากต้องการติดตามจาก @BenjaminMesing กล่าวเกี่ยวกับ NetworkError หากคุณกำลังทำผู้ให้บริการดาวน์สตรีม (map / flatMap / forEach ฯลฯ ) ใน Rx ของคุณก่อนที่คุณจะสมัครสมาชิกอาจมีโฮสต์ของประเภทข้อยกเว้นที่เป็นไปได้และไม่จำเป็นต้องมีข้อผิดพลาดบน คำขอเครือข่าย
Mark Keen

java.lang.ClassCastException: java.lang.Throwable ไม่สามารถส่งไปยัง retrofit2.HttpException
someone Somewhere

7

คุณควรทราบว่าในขณะที่Retrofit2การตอบสนองทั้งหมดที่มีรหัส2xxจะถูกเรียกจากการเรียกกลับ onNext () และรหัส HTTP ที่เหลือเช่น 4xx, 5xx จะถูกเรียกในการเรียกกลับonError ()โดยใช้Kotlin ที่ฉันได้สร้างขึ้นมาเช่น สิ่งนี้ในonError () :

mViewReference?.get()?.onMediaFetchFinished(downloadArg)
  if (it is HttpException) {
    val errorCode = it.code()
    mViewReference?.get()?.onMediaFetchFailed(downloadArg,when(errorCode){
      HttpURLConnection.HTTP_NOT_FOUND -> R.string.check_is_private
      else -> ErrorHandler.parseError(it)
    })
  } else {
    mViewReference?.get()?.onMediaFetchFailed(downloadArg, ErrorHandler.parseError(it))
  }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.