RestTemplate 和 ResponseErrorHandler:

使用RestTemplate,我正在查询远程 API 以返回预期类型(如果 HTTP 2xx)或 APIError(如果 HTTP 4xx / 5xx)的对象。


因为响应对象是不确定的,我实现了一个自定义ResponseErrorHandler并覆盖handleError(ClientHttpResponse clientHttpResponse),以便在它发生时提取 APIError。到现在为止还挺好:


@Component

public 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()。诸如此类的可恢复错误应该对用户隐藏,直到相同的错误发生多次,此时它们被认为是不可恢复的/严重的。


任何“关键”错误(例如:第二次失败、完全验证失败或传输层失败)都应报告给用户,因为没有可用的自动恢复。


管理错误处理逻辑的最优雅和最健壮的方法是什么,记住要返回的对象类型直到运行时才知道?


杨魅力
浏览 486回答 1
1回答

绝地无双

事实证明,问题本身存在谬误。我正在实现 aResponseErrorHandler因为我认为我需要它来解析响应,即使该响应返回一个 HTTP 错误代码。事实上,事实并非如此。此答案表明,可以通过捕获 aHttpStatusCodeException或使用标准将响应解析为对象RestTemplate。这否定了对自定义ResponseErrorHandler的需要,因此也不需要返回不明确类型的对象。传递错误的方法可以捕获HttpStatusCodeException,尝试刷新访问令牌,然后通过递归再次调用自身。需要一个计数器来防止无限递归,但它可以传递而不是类变量。缺点是它仍然需要在类周围传播错误管理逻辑,以及大量样板代码,但它比其他选项更整洁。public UserOrders getUserOrders(User user, Integer methodCallCount) {&nbsp; &nbsp; methodCallCount++;&nbsp; &nbsp; UserOrders userOrders;&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; userOrders = restTemplate.postForObject(USER_ORDERS_URI, request, UserOrders.class);&nbsp; &nbsp; } catch (RestClientException ex) {&nbsp; &nbsp; &nbsp; &nbsp; APIError apiError = new ObjectMapper().readValue(response.getBody(), APIError.class);&nbsp; &nbsp; &nbsp; &nbsp; if (methodCallCount < MAX_METHOD_CALLS) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (apiError.isType(ACCESS_TOKEN_EXPIRED)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; refreshVendorAccessTokenInfo(user);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; userOrders = getUserOrders(user, methodCallCount);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return userOrders;}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java