最近我开始使用 Retrofit 2,但遇到了解析空响应体的问题。我有一个服务器,它只响应 http 代码,响应正文中没有任何内容。
如何仅处理有关服务器响应的元信息(标头、状态代码等)?
编辑:
正如杰克沃顿指出的那样,
@GET("/path/to/get")
Call<Void> getMyData(/* your args here */);
与我最初的回答相比,这是最好的方法-
您可以只返回 a 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
}
});
如果你使用 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 */);
你将只有onComplete
和onError
。如果响应代码成功,它将触发,onComplete
否则将触发onError
。
If you are using rxjava, use something like :
@GET("/path/to/get")
Observable<Response<Void>> getMyData(/* your args here */);
使用 kotlin,使用返回类型Call<Void>
仍然会抛出IllegalArgumentException: Unable to create converter for retrofit2.Call<java.lang.Void>
使用 Response 而不是 Call 解决了问题
@DELETE("user/data")
suspend fun deleteUserData(): Response<Void>
你可以试试这个
Retrofit retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.addConverterFactory(new NullOnEmptyConverterFactory())
.client(okHttpClient).build();
class NullOnEmptyConverterFactory extends Converter.Factory {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return (Converter<ResponseBody, Object>) body -> {
if (body.source().exhausted()) return null;
return delegate.convert(body);
};
}
}
以下是我如何将它与 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");
}
});
}