簡體   English   中英

Spring RestTemplate 用任何非 200 OK 響應交換 POST HttpClientException

[英]Spring RestTemplate exchange POST HttpClientException with any non 200 OK response

所以我目前遇到的問題是我得到了一個

servlet [dispatcherServlet] 的 Servlet.service() 在路徑為 [] 的上下文中拋出異常 [請求處理失敗; 嵌套異常是 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() 的預期行為,我誤解了它。

RestTemplate 在遇到錯誤響應代碼時的默認行為是拋出異常。 在 4xx 的情況下是HttpClientErrorException ,在 5xx 的情況下: HttpServerErrorException (兩者都擴展了HttpStatusCodeException )。 Spring 通過使用ResponseErrorHandler來實現這一點(它是默認實現 - 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 響應一樣處理這些請求),您可以通過實現它或擴展DefaultResponseHandler來創建自己的ResponseErrorHandler實現然后在初始化期間使用 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

這里沒有什么問題。 如果您收到錯誤的狀態代碼,將拋出此異常。

您只需要將您的客戶端代碼包裝在try-catch並捕獲異常,然后對它做任何您想做的事情。

try {
    ResponseEntity<String> response = restTemplate.exchange(fruitBasketUrl, HttpMethod.POST, fruit, String.class);
} catch (HttpStatusCodeException e) {
    e.getMessage();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM