java - Retrofit2 : Error Handling

标签 java android error-handling retrofit2 simple-framework

我正在使用XML API,该API返回用户,客户,文章等的列表:

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

发生错误(例如错误的登录,停机)时,后端不会返回列表,而是返回错误消息并发送HTTP 200,但仍会:
<error>
<message>Not logged in</message>
<softver>2.4.0_231445</softver>
</error>

我想知道如何在这里正确地捕获错误。我可以在XmlObject中添加一个可选字段message,但这意味着我必须用required=false注释每个字段,以防止发生错误。我尝试了这种方法,但是由于依赖关系困惑而回滚(例如,每个列表必须具有多页成员)。我可以使用@Commit方法进行检查,但是我想强制使用一些约束,最好使用SimpleXML批注。

如何使用SimpleXML转换器处理Retrofit2中的后端错误?

最佳答案

我找到了解决方案。问题是后端错误返回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;
    }
}

关于java - Retrofit2 : Error Handling,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39077728/

相关文章:

java - 同步线程方法并发执行 - 为什么?

java - 引用父类(super class)如何使用子类方法

javascript - 在 HTTP 响应中发送大型 csv 文件类型文件

iphone - LLVM IR(中间表示)可以用于创建跨平台(iphone 和 Android)ARM 可执行文件吗?

php - 错误时,尝试包括文件并重新执行失败的功能

java - 当catch block 语句出现时

java - 如何配置简单的 Java fontconfig.properties 文件以在 Linux 上使用

java - 检查 Firestore 查询是否为空

java - 在 Android 中创建 PDF 缩略图

r - 在R中反复调用lmrob时如何处理错误