В повседневной работе вы обязательно столкнетесь с вызовами между сервисами, особенно сейчас архитектура микросервисов, так что резюмируйте самые распространенные случаи использования restTemplate и ямы, на которые вы наступили.
Использование restTemplate
Нижний уровень restTemplate вызывает метод Execute, а нижний уровень Execute вызывает doExecute, который основан на протоколе http, а нижний уровень по-прежнему является httpClient. использование.
/**
* Execute the given method on the provided URI.
* <p>The {@link ClientHttpRequest} is processed using the {@link RequestCallback};
* the response with the {@link ResponseExtractor}.
* @param url the fully-expanded URL to connect to
* @param method the HTTP method to execute (GET, POST, etc.)
* @param requestCallback object that prepares the request (can be {@code null})
* @param responseExtractor object that extracts the return value from the response (can be {@code null})
* @return an arbitrary object, as returned by the {@link ResponseExtractor}
*/
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
Обычно мы используем метод обмена из restTepmlate, этот метод более гибкий и может принимать переменные параметры, а также много перегруженных методов. Конечно, у restTemplate есть много других методов, и он соответствует стилю restFul, например PUT POST GET PATCH DELETE и так далее, есть соответствующие методы, которые можно использовать по мере необходимости. Исходный код здесь не публикуется.
Затем вставьте код варианта использования вверх:
public YourResponse sampleRestTepmlate (YourRequest request) throws Exception {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.serviceUrl);
builder.path("urlpath");
log.info("url : {}, request : {}", builder.toUriString(), JsonUtils.toJson(request));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("headername","headervalue");
headers.add("anotherway", "value");
HttpEntity<YourRequest> requestEntity = new HttpEntity<>(request, headers);
ResponseEntity<YourResponse> responseEntity = null;
try {
responseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, requestEntity,
YourResponse.class);
return responseEntity.getBody();
} catch (Exception e) {
log.error("exception:{}",e.getMessage());
}
}
Шаг на пит-авеню
Вот яма, с которой я столкнулся. При использовании restTemplate, когда ваш вызов не возвращает 200, например возвращает 400 500, в restTemplate есть DefaultResponseErrorHandler, который автоматически перехватывает эти ответы, httpstatus которых равен 400 500, и выдает вам исключение. Это означает, что когда вы также хотите получить ответ с неправильным сообщением, он вам его не даст! Он выдаст вам исключение и просто вернет вам что-то вроде 500 Internal error!WTF!
Вставьте этот дерьмовый код:
/**
* Handle the error in the given response with the given resolved status code.
* <p>This default implementation throws a {@link HttpClientErrorException} if the response status code
* is {@link org.springframework.http.HttpStatus.Series#CLIENT_ERROR}, a {@link HttpServerErrorException}
* if it is {@link org.springframework.http.HttpStatus.Series#SERVER_ERROR},
* and a {@link RestClientException} in other cases.
* @since 5.0
*/
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
switch (statusCode.series()) {
case CLIENT_ERROR:
throw new HttpClientErrorException(statusCode, response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
case SERVER_ERROR:
throw new HttpServerErrorException(statusCode, response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), response.getStatusText(),
response.getHeaders(), getResponseBody(response), getCharset(response));
}
}
План выхода из ямы
Не пугайтесь, столкнувшись с ямой, эту проблему можно решить так:
1. Вместо использования restTemplate для запроса вы можете использовать нижний слой httpClient для достижения
2. Переписать метод handleError, пользовательский ErrorHandle наследует DefaultResponseErrorHandler.
Уже написав реализацию, я выбираю путь 2 :)
@Builder
@Slf4j
public class MyErrorHandle extends DefaultResponseErrorHandler {
@Override
public void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
int status = statusCode.value();
if (status == 200 || status == 400 || status == 500) {
//do what u want to do
} else {
super.handleError(response,statusCode);
}
}
}
Затем вызовите метод setErrorHandle при инициализации restTemplate.
restTemplate.setErrorHandler(YourErrorHandle).
Как бы не упомянуть здесь.
Сертификат импорта
Иногда, когда мы вызываем сервер другой стороны, он основан на https Протокол должен импортировать сертификат, так как же нам интегрировать сертификат в restTemplate? (еще одна яма)
@Bean
public RestTemplate buildRestTemplateWithinSSl(@Value("${service.connectTimeout}") int connectTimeout,
@Value("${service.readTimeout}") int readTimeout,
@Value("${service.sslFilePath}") String filePath,
@Value("${service.sslpassword}") String sslPassword) throws Exception{
RestTemplate template = restTemplateBuilder.setConnectTimeout(connectTimeout).setReadTimeout(readTimeout).build();
String workingDirectory = BeanUtility.getWorkingDirectory();
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(new File(workingDirectory + "/" + filePath), sslPassword.toCharArray()).build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
template.setRequestFactory(factory);
return template;
}
Это эквивалентно повторному присвоению значения RequestFactory и построению для него фабрики с ssl-сертификатом.
Обратите внимание на два места здесь:
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
Одним из параметров здесь является NoopHostnameVerifier.INSTANCE, который может игнорировать ip, то есть ip или доменное имя. (Применимо к ситуации, когда другая сторона предоставляет мне сертификат и IP-адрес, и после долгих попыток я не могу дозвониться..)
Во-вторых, использование класса инструмента.Я считаю, что много раз, когда используется новый файл, легко запутаться в пути.
String workingDirectory = BeanUtility.getWorkingDirectory();
Вам не нужно беспокоиться о пути, полученном этим классом инструментов, если ваш файл jks находится на том же уровне, что и ваш пакет jar. Независимо от того, какую среду или путь он выберет, это очень удобно.
Вставьте адрес:GitHub.com/Энсон Конг/А…
Просто импортируйте локальный сертификат отладки в jdk.
Обратите внимание, как импортировать сертификат:
keytool -import -alias {别名} -file {路径\证书名}.cer -keystore "{jdk路径\jre\lib\security\cacerts}" -storepass {password} -trustcacerts
Чтобы удалить сертификат:
keytool -delete -alias {别名} -keystore "C:\Program Files\Java\jdk1.7.0_25\jre\lib\security\cacerts" -storepass {password}
Просмотр списка всех установленных сертификатов
keytool -list -v -keystore "C:\Users\1580977\Downloads\jdk1.8.0_101\jre\lib\security\cacerts" -storepass {password} >> C:\Desktop\abcd.txt
Сгенерировать файл jks (не существует по умолчанию, импортировать, если есть)
keytool -import -alias {别名} -file {证书名}.cer -keystore {命名}.jks
Наконец
RestTemplate – это клиент, предоставляемый Spring для доступа к службам Rest. RestTemplate предоставляет множество удобных методов для доступа к удаленным службам Http, которые могут значительно повысить эффективность написания клиентов.
Для получения более подробной информации о restTemplate вы можете обратиться к:nuggets.capable/post/684490… www.zifangsky.cn/1221.html
Или другие хорошие самородки.