Spring RestTemplate 与任何非 200 OK 响应交换 POST HttpClientException
Posted
技术标签:
【中文标题】Spring RestTemplate 与任何非 200 OK 响应交换 POST HttpClientException【英文标题】:Spring RestTemplate exchange POST HttpClientException with any non 200 OK response 【发布时间】:2018-10-29 16:39:13 【问题描述】:所以我目前遇到的问题是我得到了一个
Servlet.service() 用于 servlet [dispatcherServlet] 在上下文中的路径 [] 抛出异常 [请求处理失败;嵌套异常是 org.springframework.web.client.HttpClientErrorException: 404 null] 有根本原因 org.springframework.web.client.HttpClientErrorException 404 null
在我的客户端代码中,当我的服务器代码响应不是 OK 200 响应时。因此,在这种情况下,我故意在我的服务器代码中返回一个 404 响应,并使用标头和正文,并且没有标头和正文,但我仍然得到与我在服务器代码中响应的 HTTP 状态代码相同的异常和null 在这种情况下,我认为它是响应的主体。最初在我的服务器代码中,我总是返回一个ResponseEntity<>("Sent", HttpStatus.OK)
,但是由于在我的服务器代码中,我在其他地方发出 HTTP 请求,如果它以 200 OK 以外的任何内容进行响应,那么我的客户端代码将不知道它,因此我将返回从我的服务器代码中的 HTTP 请求返回的实际响应返回到我遇到此问题的客户端代码。
客户端代码
public String callFruitBasket(Fruit fruitRequest)
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Fruit> fruit = new HttpEntity<>(fruitRequest, requestHeaders);
System.out.println("Fruit headers: " + fruit.getHeaders());
ResponseEntity<String> response = restTemplate.exchange(fruitBasketUrl, HttpMethod.POST, fruit, String.class);
System.out.println("Full response: " + response);
return response.getBody();
服务器代码
@PostMapping("/fruitBasket/send")
public ResponseEntity<String> sendFruitBasket(@RequestBody Fruit fruit)
// works fine, old response
// return new ResponseEntity<>("Sent", HttpStatus.OK);
return new ResponseEntity<>("Baaad Request", HttpStatus.BAD_REQUEST);
因此,目前在我的服务器代码中,我没有在响应中添加任何标头,但我已经尝试添加 Content-Type 但是我发现我的客户端代码中仍然出现相同的异常,所以我是 100 % 确定问题出在我的客户端代码中。最初,当我通过 200 OK 响应时,完整响应的打印输出在客户端代码中很好,并显示:
Full Response: <200 OK,Sent,Content-Type=[text/plain;charset=UTF-8], Content-Length=[4], Date=[Sat, 19 May 2018 09:10:21 GMT]>
我对任何其他 Http 状态代码(如 400 和 404)的期望是相同的,但响应中使用 400 或 404 而不是 200 OK。 我已经尝试过使用客户端和服务器代码中的标头,正如我在此处的各种帖子中所读到的那样,这通常是出现此类异常时的原因,这使我相信我的客户端可能缺少一些基本的东西代码或这是 exchange() 的预期行为,我误解了它。
【问题讨论】:
您是否没有得到正确的响应代码和消息并且每次都得到 400。你能告诉我你是如何初始化 RestTemplate 的吗? @Art 现在解决了这个问题,谢谢,添加了 try catch 我可以从异常中检索所有内容。 【参考方案1】:RestTemplate 在遇到错误响应代码时的默认行为是抛出异常。如果是 4xx,它是 HttpClientErrorException
,如果是 5xx:HttpServerErrorException
(都扩展 HttpStatusCodeException
)。 Spring 通过使用 ResponseErrorHandler 实现了这一点(并且它是默认的 imlpementation - DefaultResponseErrorHandler)
处理这种情况的一种方法是抓住它们:
try
ResponseEntity<String> response = restTemplate.exchange(fruitBasketUrl, HttpMethod.POST, fruit, String.class);
catch(HttpClientErrorException e)
//handle 4xx errors
catch(HttpServerErrorException e)
//handle 5xx errors
如果您需要自定义此行为(某些其他 API 在向某些请求发送合法响应时使用这些代码,您可能希望像处理 2xx 响应一样处理这些请求),您可以通过以下方式创建自己的 ResponseErrorHandler
实现实现它或扩展DefaultResponseHandler
,然后在初始化期间使用 RestTemplate 注册您的处理程序:
public class MyResponseErrorHandler extends DefaultResponseErrorHandler
@Override
public boolean hasError(ClientHttpResponse response) throws IOException
// check if response code is an error in here or just use default implementation
@Override
public void handleError(ClientHttpResponse response) throws IOException
// handle different response codes
// (default spring behaviour is throwing an exception)
并注册:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new MyResponseErrorHandler());
// now RestTemplate's behaviour for error status codes is customized
【讨论】:
感谢您的回复,我应该可以接受 @htshame 提到的 try catch 已经对其进行了测试,但很高兴知道如果需要我可以进一步自定义它。【参考方案2】:这里没有错。如果您收到错误的状态码,将引发此异常。
您只需将客户端代码包装在 try-catch
中并捕获异常,然后对它执行任何您想做的操作。
try
ResponseEntity<String> response = restTemplate.exchange(fruitBasketUrl, HttpMethod.POST, fruit, String.class);
catch (HttpStatusCodeException e)
e.getMessage();
【讨论】:
干杯,我没想到将异常包装在 try catch >以上是关于Spring RestTemplate 与任何非 200 OK 响应交换 POST HttpClientException的主要内容,如果未能解决你的问题,请参考以下文章
WebClient 非阻塞客户端 RestTemplate 阻塞式客户端
Spring WebClient vs. RestTemplate
Spring - WebClient & RestTemplate