Làm cách nào tôi có thể xử lý phần thân phản hồi trống với Retrofit 2?


125

Gần đây tôi bắt đầu sử dụng Retrofit 2 và tôi gặp phải một vấn đề với việc phân tích cơ thể phản hồi trống. Tôi có một máy chủ chỉ phản hồi bằng mã http mà không có bất kỳ nội dung nào bên trong nội dung phản hồi.

Làm cách nào tôi chỉ có thể xử lý thông tin meta về phản hồi của máy chủ (tiêu đề, mã trạng thái, v.v.)?

Câu trả lời:


216

Biên tập:

Như Jake Wharton chỉ ra,

@GET("/path/to/get")
Call<Void> getMyData(/* your args here */);

là cách tốt nhất để đi so với phản ứng ban đầu của tôi -

Bạn chỉ có thể trả về một ResponseBody, sẽ bỏ qua phân tích phản hồi.

@GET("/path/to/get")
Call<ResponseBody> getMyData(/* your args here */);

Sau đó, trong cuộc gọi của bạn,

Call<ResponseBody> dataCall = myApi.getMyData();
dataCall.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Response<ResponseBody> response) {
        // use response.code, response.headers, etc.
    }

    @Override
    public void onFailure(Throwable t) {
        // handle failure
    }
});

58
Thậm chí tốt hơn: Sử dụng Voidkhông chỉ có ngữ nghĩa tốt hơn mà còn hiệu quả hơn một chút trong trường hợp trống và hiệu quả hơn rất nhiều trong trường hợp không trống (khi bạn không quan tâm đến cơ thể).
Jake Wharton

1
@JakeWharton Đó là hành vi tuyệt vời. Cảm ơn đã chỉ ra nó. Trả lời cập nhật.
iagreen

2
Câu trả lời chính xác. Một lý do để không sử dụng Void là nếu bạn có tài nguyên chỉ trả về phần thân khi yêu cầu không thành công và bạn muốn chuyển đổi errorBody FeedbackBody thành một số loại cụ thể hoặc phổ biến.

7
@JakeWharton Đề xuất tuyệt vời để sử dụng Void. Việc sử dụng Unittrong mã Kotlin có mang lại lợi ích tương tự Voidtrong Java cho Retrofit không?
Akshay Chordiya

6
@ akshay-chordiya Tôi mới kiểm tra, tuy nhiên , Unittrong Kotlin KHÔNG hoạt động Void. Tôi giả sử có một kiểm tra mã hóa cứng ở đâu đó.
dùng3363866

40

Nếu bạn sử dụng RxJava, thì tốt hơn nên sử dụng Completabletrong trường hợp này

Đại diện cho một tính toán hoãn lại mà không có bất kỳ giá trị nào mà chỉ cho thấy sự hoàn thành hoặc ngoại lệ. Lớp học theo một mẫu sự kiện tương tự như Reactive-Streams: onSubscribe (onError | onComplete)?

http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Completable.html

trong câu trả lời được chấp nhận:

@GET("/path/to/get")
Observable<Response<Void>> getMyData(/* your args here */);

Nếu điểm cuối trả về mã phản hồi thất bại, nó sẽ vẫn ở trong onNextvà bạn sẽ phải tự kiểm tra mã phản hồi.

Tuy nhiên, nếu bạn sử dụng Completable.

@GET("/path/to/get")
Completable getMyData(/* your args here */);

bạn sẽ chỉ có onCompleteonError. nếu mã phản hồi thành công, onCompletenó sẽ kích hoạt onError.


1
onError ThrowableĐối số sẽ chứa gì, trong trường hợp đó? Tôi thấy điều này sạch hơn, nhưng chúng ta vẫn cần phải xem mã phản hồi và cơ thể cho các lỗi.
big_m

24

Nếu bạn đang sử dụng rxjava, hãy sử dụng một cái gì đó như:

@GET("/path/to/get")
Observable<Response<Void>> getMyData(/* your args here */);

Đó là những gì tôi đang tìm kiếm! Cảm ơn!
Sirelon

Tôi đã sử dụng ResposeBody với RxJava2 và Retrofit2 cho yêu cầu PUT REST. Nó hoạt động tốt
Moti Bartov

1
Chúng tôi có API điểm cuối trả về phần thân trống khi thành công và phần tử json khi có lỗi. Nếu sử dụng Phản hồi <Void>, làm cách nào tôi có thể xử lý trường hợp lỗi?
KeNVin Favo

Bạn sử dụng lớp Phản hồi nào ở đây? Trang bị thêm hoặc OKHttps?
Matthias

1
Đây không phải là một lựa chọn tốt nếu bạn xử lý lỗi trong các trường hợp ngoại lệ .. bạn không có ngoại lệ với cách tiếp cận này, mà thay vào đó là JSON như phản hồi về lỗi
Ovi Trif

0

Đây là cách tôi sử dụng nó với Rx2 và Retrofit2, với yêu cầu PUT REST: Yêu cầu của tôi có phần thân json nhưng chỉ là mã phản hồi http với phần thân trống.

Ứng dụng khách Api:

public class ApiClient {
public static final String TAG = ApiClient.class.getSimpleName();


private DevicesEndpoint apiEndpointInterface;

public DevicesEndpoint getApiService() {


    Gson gson = new GsonBuilder()
            .setLenient()
            .create();


    OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    okHttpClientBuilder.addInterceptor(logging);

    OkHttpClient okHttpClient = okHttpClientBuilder.build();

    apiEndpointInterface = new Retrofit.Builder()
            .baseUrl(ApiContract.DEVICES_REST_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
            .create(DevicesEndpoint.class);

    return apiEndpointInterface;

}

Giao diện:

public interface DevicesEndpoint {
 @Headers("Content-Type: application/json")
 @PUT(ApiContract.DEVICES_ENDPOINT)
 Observable<ResponseBody> sendDeviceDetails(@Body Device device);
}

Sau đó, để sử dụng nó:

    private void sendDeviceId(Device device){

    ApiClient client = new ApiClient();
    DevicesEndpoint apiService = client.getApiService();
    Observable<ResponseBody> call = apiService.sendDeviceDetails(device);

    Log.i(TAG, "sendDeviceId: about to send device ID");
    call.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<ResponseBody>() {
        @Override
        public void onSubscribe(Disposable disposable) {
        }

        @Override
        public void onNext(ResponseBody body) {
            Log.i(TAG, "onNext");
        }

        @Override
        public void onError(Throwable t) {
            Log.e(TAG, "onError: ", t);

        }

        @Override
        public void onComplete() {
            Log.i(TAG, "onCompleted: sent device ID done");
        }
    });

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.