How can I handle empty response body with Retrofit

2019-01-13 03:26发布

问题:

Recently I started using Retrofit 2 and I faced an issue with parsing empty response body. I have a server which responds only with http code without any content inside the response body. How can I handle only meta information about server response (headers, status code etc)?

Thanks in advance!

回答1:

Edit:

As Jake Wharton points out,

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

is the best way to go versus my original response --

You can just return a ResponseBody, which will bypass parsing the response.

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

Then in your call,

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


回答2:

If you are using rxjava, use something like :

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


回答3:

If you use RxJava, then it's better to use Completable in this case

Represents a deferred computation without any value but only indication for completion or exception. The class follows a similar event pattern as Reactive-Streams: onSubscribe (onError|onComplete)?

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

in the accepted answer:

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

If the endpoint returns failure response code, it will still be in the onNext and you will have to check the response code yourself.

However, if you use Completable.

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

you will have only onComplete and onError. if the response code is success it will fire the onComplete else it will fire onError.



回答4:

Here is how I used it with Rx2 and Retrofit2, with PUT REST request: My request had a json body but just http response code with empty body.

The Api client:

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;

}

The interface:

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

Then to use it:

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

}