我正在使用GSON和RxJava进行改造来执行网络请求。我试图找出当Gson库无法转换它时如何获得响应。
当服务器上发生错误并且响应与Gson库尝试将响应转换为的类不匹配时,会发生这种情况。
解决方法是在我们尝试转换之前创建一个拦截器并缓存响应。但这只是糟糕的编程,因为一旦我们开始执行并发请求,问题将变得无法管理。
服务定义如下:响应类只包含状态代码和称为数据的泛型类型。
Retrofit getService() {
return new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(url)
.client(clientBuilder.build())
.build();
}
public Observable<Response<String>> userLogin(String username, String password) {
return getService().create(Account.class)
.login(username, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
我们在代码中的其他位置创建了一个请求
getService().userLogin(email, password)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onSuccess(), onError());
protected Action1<Response<String>> onSuccess(){
return new Action1<Response<String>>() {
@Override
public void call(Response<String> response) {
// Process the response
}
};
}
protected Action1<Throwable> onError(){
return new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
if (throwable instanceof HttpException) {
ResponseBody body = ((HttpException) throwable).response().errorBody();
// Handle the error
}
}
};
当服务器返回字符串以外的内容时,会出现问题。例如,对象或数组。这里GsonConverterFactory将抛出一个错误,该错误将被onError方法捕获。我想知道如何得到回应。
返回的throwable的类型为JsonSyntaxException
,遗憾的是它不包含GSON库试图转换的原始响应主体。
答案 0 :(得分:0)
昨天我向similar solution提出了一个类似的问题,但你似乎需要稍微修改一下这个问题。答案还包含对效率和内存消耗问题的一些评论。如果您使用该解决方案,您可以创建一个特殊的故障处理程序,它可以创建一个包含一些故障信息的特殊异常:
final class BadPayloadExceptionConversionThrowableConsumer
implements IConversionThrowableConsumer {
private static final int MAX_STREAM_BUFFER_LENGTH = 8 * 1024;
private static final IConversionThrowableConsumer badPayloadExceptionConversionThrowableConsumer = new BadPayloadExceptionConversionThrowableConsumer();
private BadPayloadExceptionConversionThrowableConsumer() {
}
static IConversionThrowableConsumer getBadPayloadExceptionConversionThrowableConsumer() {
return badPayloadExceptionConversionThrowableConsumer;
}
@Override
public void accept(final MediaType contentType, final long contentLength, final InputStream inputStream, final Throwable ex)
throws IOException {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(MAX_STREAM_BUFFER_LENGTH);
copy(limit(inputStream, MAX_STREAM_BUFFER_LENGTH), byteArrayOutputStream);
final ByteArrayInputStream bufferedInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
throw new BadPayloadException(ex, contentType, contentLength, bufferedInputStream);
}
static final class BadPayloadException
extends IOException {
private final MediaType contentType;
private final long contentLength;
private final InputStream inputStream;
private BadPayloadException(final Throwable cause, final MediaType contentType, final long contentLength, final InputStream inputStream) {
super(null, cause);
this.contentType = contentType;
this.contentLength = contentLength;
this.inputStream = inputStream;
}
MediaType getContentType() {
return contentType;
}
long getContentLength() {
return contentLength;
}
InputStream getInputStream() {
return inputStream;
}
}
}
而不是记录它只会抛出一个特殊的私有构造函数异常,可以在调用站点instanceof
。由于相关问题中也有注释的原因,输入流必须缓冲到某个限制(特别是为什么委托原始InputStream
而不是ResponseBody
)。现在可以使用它的方式:
service.getFooBar()
.subscribe(
out::println,
t -> {
if ( t instanceof BadPayloadException ) {
try {
final BadPayloadException badPayloadException = (BadPayloadException) t;
err.println("Content type = " + badPayloadException.getContentType());
err.println("Content length = " + badPayloadException.getContentLength());
err.print("Content = ");
copy(badPayloadException.getInputStream(), err);
} catch ( final IOException ex ) {
throw new RuntimeException(ex);
}
} else {
err.println(t.getClass());
}
}
);
请注意,copy
和limit
方法是来自Google Guava ByteStreams
的静态导入。 out
和err
分别是System.out
和System.err
的静态导入。
示例输出:
Content type = application/json
Content length = -1
Content = {#"foo":1,"bar":2}