RestTemplate - 在异常中处理响应头/响应体(RestClientException,HttpStatusCodeException)

31

在我的RESTful webservice中,如果出现错误请求(5xx)或4xx响应代码,我会自定义响应头“x-app-err-id”。

在客户端方面,我使用RestTemplate的exchange方法来进行RESTful Web服务调用。当响应代码为2xx时,一切都很好。

ResponseEntity<Component> response = restTemplate.exchange(webSvcURL,
    HttpMethod.POST, 
    requestEntity,
    Component.class);

但是如果由于请求不当(5xx)或4xx而出现异常(HttpStatusCodeException),在HttpStatusCodeException的catch块中,我会将响应(见上文)视为null,因此无法访问我在Web服务中设置的自定义标头。如何在RestTemplate中处理异常时获取响应中的自定义标头。

另外一个问题是,如果出现异常(HttpStatusCodeException),我会在响应正文中设置错误对象(json),我想知道如何在RestTemplate中访问响应正文。


您可以访问下面的线程。它包含有完整的工作代码和描述: https://dev59.com/V1oT5IYBdhLWcg3w2SYT#51805956 - Md. Sajedul Karim
3个回答

33

我最终使用ResponseErrorHandler成功了。

public class CustomResponseErrorHandler implements ResponseErrorHandler {

    private static ILogger logger = Logger.getLogger(CustomResponseErrorHandler.class);

    private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler();

    public void handleError(ClientHttpResponse response) throws IOException {

        List<String> customHeader = response.getHeaders().get("x-app-err-id");

        String svcErrorMessageID = "";
        if (customHeader != null) {
            svcErrorMessageID = customHeader.get(0);                
        }

        try {           

            errorHandler.handleError(response);

        } catch (RestClientException scx) {         

            throw new CustomException(scx.getMessage(), scx, svcErrorMessageID);
        }
    }

    public boolean hasError(ClientHttpResponse response) throws IOException {
        return errorHandler.hasError(response);
    }
}

然后通过以下配置使用这个自定义响应处理器来配置RestTemplate

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
   <property name="messageConverters">
       <list>
           <ref bean="jsonConverter" />
       </list>
   </property>    
   <property name="errorHandler" ref="customErrorHandler" />
</bean>

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
   <property name="supportedMediaTypes" value="application/json" />
</bean>

<bean id="customErrorHandler " class="my.package.CustomResponseErrorHandler">
</bean>

2
你可以扩展DefaultResponseErrorHandler而不是实现ResponseErrorHandler并创建DefaultResponseErrorHanlder的实例。 - edward_wong
你能够读取错误请求(如401、403、404等)的正文吗? - razor

29

您不需要创建自定义的错误处理程序。您可以从抛出的HttpStatusCodeException中获取主体和头信息。

try {
    ResponseEntity<Component> response = restTemplate.exchange(webSvcURL,
        HttpMethod.POST, 
        requestEntity,
        Component.class);
} catch (HttpStatusCodeException e) {
    List<String> customHeader = e.getResponseHeaders().get("x-app-err-id");
    String svcErrorMessageID = "";
    if (customHeader != null) {
        svcErrorMessageID = customHeader.get(0);                
    }
    throw new CustomException(e.getMessage(), e, svcErrorMessageID);
    // You can get the body too but you will have to deserialize it yourself
    // e.getResponseBodyAsByteArray()
    // e.getResponseBodyAsString()
}

0
如果您使用全局异常处理程序,请添加以下方法或检查此链接,将以下方法添加到 GlobalExceptionHandler 类中:

https://www.javaguides.net/2018/09/spring-boot-2-exception-handling-for-rest-apis.html

@ExceptionHandler({HttpClientErrorException.class, HttpStatusCodeException.class, HttpServerErrorException.class})
    @ResponseBody
    public ResponseEntity<Object> httpClientErrorException(HttpStatusCodeException e) throws IOException {
        BodyBuilder bodyBuilder = ResponseEntity.status(e.getRawStatusCode()).header("X-Backend-Status", String.valueOf(e.getRawStatusCode()));
        if (e.getResponseHeaders().getContentType() != null) {
            bodyBuilder.contentType(e.getResponseHeaders().getContentType());
        }
        return bodyBuilder.body(e.getResponseBodyAsString());
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接