How can I handle empty response body with Retrofit 2?

后端 未结 4 1868
悲&欢浪女
悲&欢浪女 2020-11-30 20:33

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

相关标签:
4条回答
  • 2020-11-30 20:59

    If you are using rxjava, use something like :

    @GET("/path/to/get")
    Observable<Response<Void>> getMyData(/* your args here */);
    
    0 讨论(0)
  • 2020-11-30 21:09

    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
        }
    });
    
    0 讨论(0)
  • 2020-11-30 21:14

    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");
            }
        });
    
    }
    
    0 讨论(0)
  • 2020-11-30 21:16

    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.

    0 讨论(0)
提交回复
热议问题