为了账号安全,请及时绑定邮箱和手机立即绑定

RestTemplate 和 ResponseErrorHandler:

RestTemplate 和 ResponseErrorHandler:

杨魅力 2021-06-07 13:27:48
使用RestTemplate,我正在查询远程 API 以返回预期类型(如果 HTTP 2xx)或 APIError(如果 HTTP 4xx / 5xx)的对象。因为响应对象是不确定的,我实现了一个自定义ResponseErrorHandler并覆盖handleError(ClientHttpResponse clientHttpResponse),以便在它发生时提取 APIError。到现在为止还挺好:@Componentpublic class RemoteAPI {    public UserOrders getUserOrders(User user) {        addAuthorizationHeader(httpHeaders, user.getAccessToken());        HttpEntity<TokenRequest> request = new HttpEntity<>(HEADERS);        return restTemplate.postForObject(CUSTOMER_ORDERS_URI, request, UserOrders.class);    }    private class APIResponseErrorHandler implements ResponseErrorHandler {        @Override        public void handleError(ClientHttpResponse response) {            try {                APIError apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);            } catch ...        }    }    private void refreshAccessToken(User user) {        addAuthorizationHeader(httpHeaders, user.getAccessSecret());        HttpEntity<TokenRequest> request = new HttpEntity<>(HEADERS);        user.setAccessToken(restTemplate.postForObject(TOKEN_REFRESH_URI, request, AccessToken.class));    }}挑战在于getUserOrders(),或类似的 API 调用,偶尔会因“可恢复”错误而失败;例如,API 访问令牌可能已过期。然后我们应该refreshAccessToken()在重新尝试之前进行 API 调用getUserOrders()。诸如此类的可恢复错误应该对用户隐藏,直到相同的错误发生多次,此时它们被认为是不可恢复的/严重的。任何“关键”错误(例如:第二次失败、完全验证失败或传输层失败)都应报告给用户,因为没有可用的自动恢复。管理错误处理逻辑的最优雅和最健壮的方法是什么,记住要返回的对象类型直到运行时才知道?
查看完整描述

1 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

事实证明,问题本身存在谬误。


我正在实现 aResponseErrorHandler因为我认为我需要它来解析响应,即使该响应返回一个 HTTP 错误代码。事实上,事实并非如此。


此答案表明,可以通过捕获 aHttpStatusCodeException或使用标准将响应解析为对象RestTemplate。这否定了对自定义ResponseErrorHandler的需要,因此也不需要返回不明确类型的对象。传递错误的方法可以捕获HttpStatusCodeException,尝试刷新访问令牌,然后通过递归再次调用自身。需要一个计数器来防止无限递归,但它可以传递而不是类变量。


缺点是它仍然需要在类周围传播错误管理逻辑,以及大量样板代码,但它比其他选项更整洁。


public UserOrders getUserOrders(User user, Integer methodCallCount) {

    methodCallCount++;

    UserOrders userOrders;

    try {

        userOrders = restTemplate.postForObject(USER_ORDERS_URI, request, UserOrders.class);

    } catch (RestClientException ex) {

        APIError apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);

        if (methodCallCount < MAX_METHOD_CALLS) {

            if (apiError.isType(ACCESS_TOKEN_EXPIRED)) {

                refreshVendorAccessTokenInfo(user);

                userOrders = getUserOrders(user, methodCallCount);

            }

        }

    }

    return userOrders;

}


查看完整回答
反对 回复 2021-06-10
  • 1 回答
  • 0 关注
  • 485 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信