Retrofit2:错误处理
Retrofit2: Error Handling
我正在使用 XML API,其中 returns 用户、客户、文章等列表:
<userlist access="ro">
<multipage>
<!-- Info about nums of pages, elements per page etc. -->
</multipage>
<user access="ro">
<surname access="rw" type="string">Jon</surname>
<lastname access="rw" type="string">Doe</lastname>
<scannerpin access="ro" type="int">1234</scannerpin>
</user>
<user>
<!-- ... -->
</user>
</userlist>
目前,我的 POJO 看起来像这样:
@Root(name="userlist")
public class User extends XmlObject {
@Element
private XmlElement surname;
@Element
private XmlElement lastname;
@Element
private XmlElement scannerpin;
}
@Root(strict=false)
/* XXX no support for generics in SimpleXML. TODO Find better solution */
public class XmlUserList extends XmlList<User> {
/**
* Constructor for XmlUserList
*
* @param multipage
*/
public XmlUserList(@Element(name = "multipage") Multipage multipage) {
super(multipage);
}
}
public class XmlElement extends XmlNode {
protected static final String rcsid = "$Id: XmlElement.java 29660 2016-08-17 15:08:39Z jb $";
/**
* The element's value
*/
@Text(required=false)
String value;
/**
* Default constructor for XmlElement
*/
public XmlElement() {
}
/**
* Getter for value
* @return this.value
*/
public String getValue() {
return this.value != null ? this.value : "";
}
/**
* Setter for value
* @param value The new value
* @throws UnsupportedOperationException Iff this element is readOnly
*/
public void setValue(String value) throws UnsupportedOperationException {
this.value = value;
}
public void setValue(Integer value) {
this.value = String.valueOf(value);
}
}
public abstract class XmlList<T> extends XmlNode {
protected static final String rcsid = "$Id: XmlList.java 29660 2016-08-17 15:08:39Z jb $";
/**
* List entries
*/
@ElementListUnion({
@ElementList(inline = true, name = "user", type = User.class,required=false),
@ElementList(inline = true, name = "customer", type = Customer.class,required=false),
@ElementList(inline = true, name = "article", type = Article.class,required=false)
})
private List<T> list;
/**
* Multipage object
*/
private Multipage multipage;
/**
* Constructor for XmlList
*/
public XmlList(@Element(name="multipage") Multipage multipage) {
this.multipage = multipage;
}
/**
* getter for list
* @return this.list
*/
public List<T> getList() {
return (this.list);
}
public void setList(List<T> list) {
this.list = list;
}
/**
* Getter for Multipage
* @return this.multipage
*/
@Element(name="multipage")
public Multipage getMultipage() {
return (this.multipage);
}
}
发生错误(例如错误登录、停机),后端不会return一个列表,而是一个错误消息并发送 HTTP 200,anway:
<error>
<message>Not logged in</message>
<softver>2.4.0_231445</softver>
</error>
我想知道如何在此处以正确的方式捕获错误。我可以向 XmlObject 添加一个可选字段 message
,但这意味着我必须用 required=false
注释每个字段以防止错误异常。我尝试了这种方法,但由于依赖性混乱而回滚(例如,每个列表必须有一个多页成员)。我可以在 @Commit
方法中检查这一点,但是我想强制执行几个约束,最好使用 SimpleXML 注释。
如何使用 SimpleXML 转换器处理 Retrofit2 中的后端错误?
我找到了解决方案。问题是后端 returns HTTP/1.1 200 OK
出错。我编写了一个拦截器,它检查响应是否可以解析为 ApiError
对象,如果可以,则将响应的 HTTP 状态代码覆盖为 HTTP/1.1 400 Bad Request
.
final class ErrorInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
Response.Builder responseBuilder = originalResponse.newBuilder();
/*
* get body from response. caution! .string() cannot be called more
* than once, so a new response is built with the old response's body
*/
String bodyString = originalResponse.body().string();
// if response is an error: override response code to 400
if (isError(bodyString)) {
responseBuilder.code(400);
}
// clone response into new one
responseBuilder.body(
ResponseBody.create(originalResponse.body().contentType(),
bodyString));
return responseBuilder.build();
}
public boolean isError(String body) {
Serializer ser = new Persister();
try {
return ser.validate(ErrorUtils.ApiError.class, body);
// ser.validate() will throw if body can't be read into ApiError.class
} catch (Exception e) {
return false;
}
}
}
@Root(name="error")
public class ApiError {
@Element
private String message;
@Element
private String softver;
public ApiError(@Element(name="message") String message, @Element(name="softver") String softver) {
this.message = message;
this.softver = softver;
}
public String getMessage() {
return message;
}
public String getSoftver() {
return softver;
}
}
我正在使用 XML API,其中 returns 用户、客户、文章等列表:
<userlist access="ro">
<multipage>
<!-- Info about nums of pages, elements per page etc. -->
</multipage>
<user access="ro">
<surname access="rw" type="string">Jon</surname>
<lastname access="rw" type="string">Doe</lastname>
<scannerpin access="ro" type="int">1234</scannerpin>
</user>
<user>
<!-- ... -->
</user>
</userlist>
目前,我的 POJO 看起来像这样:
@Root(name="userlist")
public class User extends XmlObject {
@Element
private XmlElement surname;
@Element
private XmlElement lastname;
@Element
private XmlElement scannerpin;
}
@Root(strict=false)
/* XXX no support for generics in SimpleXML. TODO Find better solution */
public class XmlUserList extends XmlList<User> {
/**
* Constructor for XmlUserList
*
* @param multipage
*/
public XmlUserList(@Element(name = "multipage") Multipage multipage) {
super(multipage);
}
}
public class XmlElement extends XmlNode {
protected static final String rcsid = "$Id: XmlElement.java 29660 2016-08-17 15:08:39Z jb $";
/**
* The element's value
*/
@Text(required=false)
String value;
/**
* Default constructor for XmlElement
*/
public XmlElement() {
}
/**
* Getter for value
* @return this.value
*/
public String getValue() {
return this.value != null ? this.value : "";
}
/**
* Setter for value
* @param value The new value
* @throws UnsupportedOperationException Iff this element is readOnly
*/
public void setValue(String value) throws UnsupportedOperationException {
this.value = value;
}
public void setValue(Integer value) {
this.value = String.valueOf(value);
}
}
public abstract class XmlList<T> extends XmlNode {
protected static final String rcsid = "$Id: XmlList.java 29660 2016-08-17 15:08:39Z jb $";
/**
* List entries
*/
@ElementListUnion({
@ElementList(inline = true, name = "user", type = User.class,required=false),
@ElementList(inline = true, name = "customer", type = Customer.class,required=false),
@ElementList(inline = true, name = "article", type = Article.class,required=false)
})
private List<T> list;
/**
* Multipage object
*/
private Multipage multipage;
/**
* Constructor for XmlList
*/
public XmlList(@Element(name="multipage") Multipage multipage) {
this.multipage = multipage;
}
/**
* getter for list
* @return this.list
*/
public List<T> getList() {
return (this.list);
}
public void setList(List<T> list) {
this.list = list;
}
/**
* Getter for Multipage
* @return this.multipage
*/
@Element(name="multipage")
public Multipage getMultipage() {
return (this.multipage);
}
}
发生错误(例如错误登录、停机),后端不会return一个列表,而是一个错误消息并发送 HTTP 200,anway:
<error>
<message>Not logged in</message>
<softver>2.4.0_231445</softver>
</error>
我想知道如何在此处以正确的方式捕获错误。我可以向 XmlObject 添加一个可选字段 message
,但这意味着我必须用 required=false
注释每个字段以防止错误异常。我尝试了这种方法,但由于依赖性混乱而回滚(例如,每个列表必须有一个多页成员)。我可以在 @Commit
方法中检查这一点,但是我想强制执行几个约束,最好使用 SimpleXML 注释。
如何使用 SimpleXML 转换器处理 Retrofit2 中的后端错误?
我找到了解决方案。问题是后端 returns HTTP/1.1 200 OK
出错。我编写了一个拦截器,它检查响应是否可以解析为 ApiError
对象,如果可以,则将响应的 HTTP 状态代码覆盖为 HTTP/1.1 400 Bad Request
.
final class ErrorInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
Response.Builder responseBuilder = originalResponse.newBuilder();
/*
* get body from response. caution! .string() cannot be called more
* than once, so a new response is built with the old response's body
*/
String bodyString = originalResponse.body().string();
// if response is an error: override response code to 400
if (isError(bodyString)) {
responseBuilder.code(400);
}
// clone response into new one
responseBuilder.body(
ResponseBody.create(originalResponse.body().contentType(),
bodyString));
return responseBuilder.build();
}
public boolean isError(String body) {
Serializer ser = new Persister();
try {
return ser.validate(ErrorUtils.ApiError.class, body);
// ser.validate() will throw if body can't be read into ApiError.class
} catch (Exception e) {
return false;
}
}
}
@Root(name="error")
public class ApiError {
@Element
private String message;
@Element
private String softver;
public ApiError(@Element(name="message") String message, @Element(name="softver") String softver) {
this.message = message;
this.softver = softver;
}
public String getMessage() {
return message;
}
public String getSoftver() {
return softver;
}
}