Spring RestTemplate обмен POST HttpClientException с любым ответом, отличным от 200 OK

Итак, текущая проблема, с которой я столкнулся, заключается в том, что я получаю

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 404 null] with root cause 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 Status, такого как 400 и 404, будет таким же, но с 400 или 404 в ответе вместо 200 OK. Я пробовал поиграть с заголовками как в клиентском, так и в серверном коде, поскольку я читал в различных сообщениях здесь, что это обычно является причиной получения такого типа исключения, что заставляет меня думать, что в моем клиенте может быть чего-то фундаментального. code или что это ожидаемое поведение для exchange () и что я неправильно его понимаю.

Вы не получаете правильный код ответа и сообщение, а каждый раз получаете 400? Можете ли вы также сказать, как вы инициализировали RestTemplate.

Art 19.05.2018 13:43

@Art Решил проблему, спасибо, добавив try catch, я могу получить все из исключения.

iranicus 19.05.2018 15:56
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
7
2
10 100
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Здесь нет ничего плохого. Это исключение будет выдано, если вы получите ошибочный код состояния.

Вам просто нужно обернуть свой клиентский код в try-catch и перехватить исключение, а затем сделать с ним все, что вы хотите.

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

Ура, мне не пришло в голову заключить исключение в try catch> <

iranicus 19.05.2018 15:53

Поведение 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), вы можете создать свою собственную реализацию 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

Спасибо за ответ, я должен быть в порядке с попыткой catch @htshame, упомянутой уже протестировавшей его, но приятно знать, что я могу настроить его дальше, если это необходимо.

iranicus 19.05.2018 15:58

Другие вопросы по теме