Ответ 1
Используйте методы RestTemplate#exchange(..)
, которые возвращают ResponseEntity
. Это дает вам доступ к строке состояния и заголовкам (и, очевидно, к телу).
Я использую RestTemplate
, чтобы сделать HTTP-вызов нашей службе, который возвращает простой ответ JSON. Мне не нужно разбирать этот JSON вообще. Мне просто нужно вернуть все, что я получаю от этой службы.
Итак, я сопоставляю это с String.class
и возвращаю фактический JSON response
как строку.
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
return response;
Теперь вопрос -
Я пытаюсь извлечь HTTP Status codes
после попадания в URL. Как я могу извлечь код состояния HTTP из вышеуказанного кода? Нужно ли мне вносить какие-либо изменения в то, как я это делаю сейчас?
Обновление: -
Это то, что я пробовал, и я могу получить ответ назад и код состояния. Но всегда ли мне нужно установить HttpHeaders
и Entity
объект, как показано ниже, я это делаю?
RestTemplate restTemplate = new RestTemplate();
//and do I need this JSON media type for my use case?
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//set my entity
HttpEntity<Object> entity = new HttpEntity<Object>(headers);
ResponseEntity<String> out = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
System.out.println(out.getBody());
System.out.println(out.getStatusCode());
Пара вопросов. Мне нужно иметь MediaType.APPLICATION_JSON
, поскольку я просто делаю вызов url, который возвращает ответ, он может возвращать JSON или XML или простую строку.
Используйте методы RestTemplate#exchange(..)
, которые возвращают ResponseEntity
. Это дает вам доступ к строке состояния и заголовкам (и, очевидно, к телу).
Если вы не хотите оставлять прекрасную абстракцию вокруг методов RestTemplate.get/postForObject...
, подобных мне, и не любите сражаться с шаблонами, необходимыми при использовании RestTemplate.exchange...
(Request- and ResponseEntity, HttpHeaders и т.д.), s другой вариант для доступа к кодам HttpStatus.
Просто обведите обычный RestTemplate.get/postForObject...
с помощью try/catch для org.springframework.web.client.HttpClientErrorException
и org.springframework.web.client.HttpServerErrorException
, как в этом примере:
try {
return restTemplate.postForObject("http://your.url.here", "YourRequestObjectForPostBodyHere", YourResponse.class);
} catch (HttpClientErrorException | HttpServerErrorException httpClientOrServerExc) {
if(HttpStatus.NOT_FOUND.equals(httpClientOrServerExc.getStatusCode())) {
// your handling of "NOT FOUND" here
// e.g. throw new RuntimeException("Your Error Message here", httpClientOrServerExc);
}
else {
// your handling of other errors here
}
Здесь org.springframework.web.client.HttpServerErrorException
добавляется для ошибок с 50x
.
Теперь вы можете просто реагировать на все требуемые коды состояния - кроме соответствующего, который соответствует вашему HTTP-методу - например, GET
и 200
, который не будет обрабатываться как исключение, так как это соответствующий. Но это должно быть прямо, если вы реализуете/потребляете сервисы RESTful:)
private RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(url,HttpMethod.GET, requestEntity,String.class);
ответ содержит "body", "headers" и "statusCode"
чтобы получить statusCode: response.getStatusCode();
Могут быть несколько более хитрые случаи использования, которые могут быть у кого-то (как и я). Рассмотрим следующее:
Поддержка объекта страницы, чтобы использовать его с RestTemplate и ParameterizedTypeReference:
RestPageResponse
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
public class RestResponsePage<T> extends PageImpl<T>{
private static final long serialVersionUID = 3248189030448292002L;
public RestResponsePage(List<T> content, Pageable pageable, long total) {
super(content, pageable, total);
}
public RestResponsePage(List<T> content) {
super(content);
}
public RestResponsePage() {
super(new ArrayList<T>());
}
}
Использование ParameterizedTypeReference
приведет к следующему:
ParameterizedTypeReference<RestResponsePage<MyObject>> responseType =
new ParameterizedTypeReference<RestResponsePage<MyObject>>() {};
HttpEntity<RestResponsePage<MyObject>> response = restTemplate.exchange(oauthUrl, HttpMethod.GET, entity, responseType);
Вызов #exchange:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<?> entity = new HttpEntity<>(headers);
response = restTemplate.exchange("localhost:8080/example", HttpMethod.GET, entity, responseType);
Теперь вот "сложная" часть.
Попытка обмена вызовами getStatusCode
будет невозможна, потому что компилятор, к сожалению, не будет знать о "предполагаемом" типе response
.
Это объясняется тем, что генерические средства реализуются с помощью стирания типа, которое удаляет всю информацию о родовых типах во время компиляции (подробнее - источник)
((ResponseEntity<RestResponsePage<MyObject>>) response).getStatusCode()
В этом случае вам нужно явно передать переменную в требуемый класс, чтобы получить statusCode
(и/или другие атрибуты)!
exchange (...) работает, но если вы хотите меньше кода, вы можете использовать
org.springframework.boot.test.web.client.TestRestTemplate.getForEntity(...)
который возвращает сущность, содержащую StatusCode. Измените ваш пример кода на это:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
HttpStatus statusCode = response.getStatusCode();
Чтобы проверить это, вы можете использовать этот фрагмент из моего модульного теста:
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
assertResponseHeaderIsCorrect(response, HttpStatus.OK);
/**
* Test the basics of the response, non-null, status expected, etc...
*/
private void assertResponseHeaderIsCorrect(ResponseEntity<String> response, HttpStatus expectedStatus) {
assertThat(response).isNotNull();
assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON_UTF8);
assertThat(response.getStatusCode()).isEqualTo(expectedStatus);
}
Достаточно HttpStatus statusCode = ((ResponseEntity<Object>) responseOfEsoft).getStatusCode();
этот большой объем кода. HttpStatus statusCode = ((ResponseEntity<Object>) responseOfEsoft).getStatusCode();
Если вы хотите получить все HTTPS-состояния из RestTemplate, включая 4XX и 5XX, вам нужно будет предоставить ResponseErrorHandler для restTemplate, так как обработчик по умолчанию выдаст исключение в случае 4XX или 5XX
Мы могли бы сделать что-то подобное:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
@Override
public boolean hasError(HttpStatus statusCode) {
return false;
}
});
ResponseEntity<YourResponse> responseEntity =
restTemplate.getForEntity("http://your.url.here", YourResponse.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.XXXX);