如何使用Retrofit 2处理空的响应正文?


125

最近,我开始使用Retrofit 2,并且在解析空白响应正文时遇到问题。我有一个仅用http代码响应的服务器,响应主体内部没有任何内容。

如何仅处理有关服务器响应的元信息(标头,状态代码等)?

Answers:


216

编辑:

杰克·沃顿(Jake Wharton)指出,

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

与我最初的回应相比是最好的方法-

您可以只返回ResponseBody,这将绕过解析响应。

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

然后在您的通话中

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
甚至更好:使用Void这种方法不仅具有更好的语义,而且在空情况下(在)非空情况下(当您只是不在乎身体时)效率更高(略)。
杰克·沃顿

1
@JakeWharton这是很好的行为。感谢您指出。答案已更新。
iagreen

2
好答案。不使用Void的原因之一是,如果您的资源仅在请求不成功时返回一个正文,并且您想将errorBody ResponseBody转换为某些特定或通用类型。

7
@JakeWharton建议使用VoidUnit在Kotlin代码中使用会带来与VoidJava for Retrofit 相同的好处吗?
Akshay Chordiya

6
我刚刚检查过的@ akshay-chordiya,Unit在Kotlin中不起作用,Void但是可以。我假设某处有一个硬编码的支票。
user3363866

40

如果您使用RxJava,那么Completable在这种情况下最好使用

表示没有任何值,仅指示完成或异常的延迟计算。该类遵循与Reactive-Streams类似的事件模式:onSubscribe(onError | onComplete)?

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

在接受的答案中:

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

如果端点返回失败响应代码,则它仍将位于 onNext并且您必须自己检查响应代码。

但是,如果使用Completable

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

您将只有onCompleteonError。如果响应代码成功,它将触发,onComplete否则将触发onError


1
onError Throwable在这种情况下,论点将包含什么?我找到了这种清洁器,但是我们经常仍然需要查看响应代码和失败的正文。
big_m

24

如果您使用的是rxjava,请使用类似以下内容的代码:

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

那就是我所发现的!谢谢!
Sirelon

我已经将ResposeBody与RxJava2和Retrofit2一起用于PUT REST请求。工作正常
Moti Bartov

1
我们有一个端点API,该API在成功时返回空主体,在错误时返回json主体。如果使用Response <Void>,如何处理错误情况?
KeNVin Favo '18

您在这里使用哪个Response类?改型还是OKHttps?
Matthias

1
如果您对异常进行错误处理,这不是一个好选择。.这种方法不会导致异常,而是对错误进行响应时使用JSON
Ovi Trif

0

这是我将其与Rx2和Retrofit2以及PUT REST请求一起使用的方式:我的请求具有json主体,但只有http响应代码,主体为空。

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;

}

界面:

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

然后使用它:

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

}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.