私は古典的な顔の質問だけでなく、マイクロ技術の共有サービス、心配です、あなたは、最新の知識を得ることができます
マイクロサービスでは、rest
サービスコール同士は非常に一般的ですが、どのように我々は優雅に呼ばない、実際には、Springフレームワークが使用するRestTemplate
優雅クラスすることができrest
、互いを呼び出すためのサービス、それが簡単になり、http
通信サービス、統一RESTful
規格、カプセル化http
リンクは、操作が使用するのは簡単です、あなたもRestTemplateモードの必要な定義をカスタマイズすることができます。どこで:
RestTemplate
既定のHttpMessageConverter
インスタンスHTTP
にメッセージPOJO
またはからPOJO
変換されたHTTP
メッセージ。デフォルトのマスターによって登録されているmime
コンバータの種類を、だけでなく、できるsetMessageConverters
カスタムコンバータを登録します。RestTemplate
デフォルト使用DefaultResponseErrorHandler
40XのBad Request
か50Xinternal
異常なerror
エラー情報の取得を。RestTemplate
また、インターセプター使用することができinterceptor
、リクエストリンクトラッキングで行われ、統一ヘッドの設定を。
これはRestTemplate
また、多数の定義REST
に対応ほとんどがインタラクティブリソースの方法HTTP
以下のように、この方法は:
方法 | 解決 |
---|---|
削除() | HTTPは、特定のリソースのURLにDELETE操作の実行 |
交換() | URLに特定のHTTPメソッドを実行し、ResponseEntityは、オブジェクトが含まれて返します |
実行() | 特定のHTTP URLで実行される方法では、反応マップから得られるオブジェクト本体を返します |
getForEntity() | HTTP GETリクエストを送信し、それはレスポンスボディResponseEntityはにマッピングされたオブジェクトが含まれて返します |
getForObject() | HTTP GETリクエストを送信し、その要求がターゲット本体にマッピングされる返します |
postForEntity() | URLへのPOSTデータは、ResponseEntityを備えたオブジェクトを返します。 |
postForObject() | 、応答は、オブジェクト整合体が形成されているURLにPOSTデータを返します |
headForHeaders() | HTTP HEADリクエストを送信し、それが特定のリソースのURLを含むHTTPヘッダを返します |
optionsForAllow() | HTTPのOPTIONS要求を送信し、特定のURLの許可ヘッダ情報を返します |
postForLocation() | URLへのPOSTデータは、新しく作成されたリソースのURLを返します。 |
プット() | 特定のURLへのリソースのPUT |
1. RestTemplateソース
1.1デフォルトのコールのリンク
restTemplate
場合は、API呼び出し、デフォルトのコールチェーン:
###########1.使用createRequest创建请求########
resttemplate->execute()->doExecute()
HttpAccessor->createRequest()
//获取拦截器Interceptor,InterceptingClientHttpRequestFactory,SimpleClientHttpRequestFactory
InterceptingHttpAccessor->getRequestFactory()
//获取默认的SimpleBufferingClientHttpRequest
SimpleClientHttpRequestFactory->createRequest()
#######2.获取响应response进行处理###########
AbstractClientHttpRequest->execute()->executeInternal()
AbstractBufferingClientHttpRequest->executeInternal()
###########3.异常处理#####################
resttemplate->handleResponse()
##########4.响应消息体封装为java对象#######
HttpMessageConverterExtractor->extractData()
复制代码
1.2 restTemplate-> doExecute()
デフォルトのコールチェーンでは、restTemplate
API呼び出しが呼び出すdoExecute
メソッドを、この方法は、以下のステップを実行することができる、主に次のとおりです。
1)使用してcreateRequest
作成要求、フェッチレスポンス
)2 応答異常例外ハンドリングか否かを判断する
)3をJavaオブジェクト体としてカプセル化された応答メッセージを
@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 {
//使用createRequest创建请求
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
//获取响应response进行处理
response = request.execute();
//异常处理
handleResponse(url, method, response);
//响应消息体封装为java对象
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();
}
}
}
复制代码
1.3 InterceptingHttpAccessor-> getRequestFactory()
デフォルトのコールチェーンでは、InterceptingHttpAccessor的getRequestFactory()
方法は、ない場合interceptor
インターセプター、デフォルトに戻ってくるSimpleClientHttpRequestFactory
、そうでない場合は、返すInterceptingClientHttpRequestFactory
にrequestFactory
、できるresttemplate.setInterceptors
カスタムインターセプタを設定しますinterceptor
。
//Return the request factory that this accessor uses for obtaining client request handles.
public ClientHttpRequestFactory getRequestFactory() {
//获取拦截器interceptor(自定义的)
List<ClientHttpRequestInterceptor> interceptors = getInterceptors();
if (!CollectionUtils.isEmpty(interceptors)) {
ClientHttpRequestFactory factory = this.interceptingRequestFactory;
if (factory == null) {
factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
this.interceptingRequestFactory = factory;
}
return factory;
}
else {
return super.getRequestFactory();
}
}
复制代码
その後、呼び出しSimpleClientHttpRequestFactory的createRequest
接続を作成するには:
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
}
else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
}
}
复制代码
1.4 resttemplate->のhandleResponse()
デフォルトのコールチェーンにresttemplate的handleResponse
、例外処理を含む、応答を処理する例外処理を呼び出すことができ、setErrorHandler
カスタムメソッドを設定しErrorHandler
、異常判定処理及び要求に対する応答を実施しました。カスタマイズErrorHandler
達成する必要ResponseErrorHandler
インターフェイスを、しかしSpring boot
また、デフォルトの実装を提供しDefaultResponseErrorHandler
、継承によってそのクラスを達成することも可能ですErrorHandler
。
DefaultResponseErrorHandler
40XのデフォルトBad Request
または50倍internal
異常error
のエラー情報をキャプチャ。あなたは情報サービス自体によってスローされた例外をキャッチしたい場合、それはを通じて自己実現を必要とします。RestTemplate
ErrorHandler
ResponseErrorHandler errorHandler = getErrorHandler();
//判断响应是否有异常
boolean hasError = errorHandler.hasError(response);
if (logger.isDebugEnabled()) {
try {
int code = response.getRawStatusCode();
HttpStatus status = HttpStatus.resolve(code);
logger.debug("Response " + (status != null ? status : code));
}catch (IOException ex) {
// ignore
}
}
//有异常进行异常处理
if (hasError) {
errorHandler.handleError(url, method, response);
}
}
复制代码
1.5 HttpMessageConverterExtractor-> extractData()
デフォルトの呼び出しチェーンでは、HttpMessageConverterExtractor
されてextractData
カプセル化するための応答メッセージとして行うjava
オブジェクトを、あなたが使用する必要があるmessage
カスタムの方法を追加することにより、コンバータを増加させることができるmessageConverter
。第一の従来の取得messageConverter
、カスタム、その後messageConverter
追加。
よれば、利用可能なソースコード、追加の実施形態を使用して、元の防止失われ、ソース。restTemplate
setMessageConverters
messageConverter
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
//检验
validateConverters(messageConverters);
// Take getMessageConverters() List as-is when passed in here
if (this.messageConverters != messageConverters) {
//先清除原有的messageConverter
this.messageConverters.clear();
//后加载重新定义的messageConverter
this.messageConverters.addAll(messageConverters);
}
}
复制代码
HttpMessageConverterExtractor的extractData
出典:
MessageBodyClientHttpResponseWrapper responseWrapper = new MessageBodyClientHttpResponseWrapper(response);
if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
return null;
}
//获取到response的ContentType类型
MediaType contentType = getContentType(responseWrapper);
try {
//依次循环messageConverter进行判断是否符合转换条件,进行转换java对象
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
//会根据设置的返回类型responseType和contentType参数进行匹配,选择合适的MessageConverter
if (messageConverter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter<?> genericMessageConverter =
(GenericHttpMessageConverter<?>) messageConverter;
if (genericMessageConverter.canRead(this.responseType, null, contentType)) {
if (logger.isDebugEnabled()) {
ResolvableType resolvableType = ResolvableType.forType(this.responseType);
logger.debug("Reading to [" + resolvableType + "]");
}
return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);
}
}
if (this.responseClass != null) {
if (messageConverter.canRead(this.responseClass, contentType)) {
if (logger.isDebugEnabled()) {
String className = this.responseClass.getName();
logger.debug("Reading to [" + className + "] as \"" + contentType + "\"");
}
return (T) messageConverter.read((Class) this.responseClass, responseWrapper);
}
}
}
}
.....
}
复制代码
contentTypeとmessageConverter 1.6との間の関係
でに基づいて見られるプロセス、選択、メッセージ変換読み取り可能です。次のような関係は以下のとおりです。HttpMessageConverterExtractor
extractData
contentType
responseClass
messageConverter
クラス名 | サポートされているのJavaType | サポートされているのMediaType |
---|---|---|
ByteArrayHttpMessageConverter | バイト[] | アプリケーション/ octet-streamと、* / * |
StringHttpMessageConverter | 弦 | text / plainで、* / * |
ResourceHttpMessageConverter | 資源 | * / * |
SourceHttpMessageConverter | ソース | / * + xmlのアプリケーション/ XML、text / xmlで、アプリケーション |
AllEncompassingFormHttpMessageConverter | 地図<K、リスト<?>> | アプリケーション/ x-www-form-urlencodedで、マルチパート/フォームデータ |
MappingJackson2HttpMessageConverter | オブジェクト | アプリケーション/ JSON、アプリケーション/ * + JSON |
Jaxb2RootElementHttpMessageConverter | オブジェクト | / * + xmlのアプリケーション/ XML、text / xmlで、アプリケーション |
JavaSerializationConverter | Serializableを | X-javaのシリアライゼーション;のcharset = UTF-8 |
FastJsonHttpMessageConverter | オブジェクト | * / * |
2. springboot統合RestTemplate
ソースコード解析の研究によれば、簡単に、簡単にRestTemplateに優雅なカスタム例外処理、追加など、プロジェクトで使用することができますMessageConverter
し、インターセプタをinterceptor
。本明細書で使用する場合、例はdemo
、以下のページを参照してください。
2.1輸入依存:(ウェブスタートに統合RestTemplate)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
复制代码
2.2. RestTemplat配置:
- 使用
ClientHttpRequestFactory
たとえば、プロパティRestTemplatの構成パラメータをConnectTimeout
、ReadTimeout
。 - カスタムの追加
interceptor
インターセプタ、例外処理を、 - 追加
message
コンバータ; - カスタム例外ハンドラを設定します。
@Configuration
public class RestTemplateConfig {
@Value("${resttemplate.connection.timeout}")
private int restTemplateConnectionTimeout;
@Value("${resttemplate.read.timeout}")
private int restTemplateReadTimeout;
@Bean
//@LoadBalanced
public RestTemplate restTemplate( ClientHttpRequestFactory simleClientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate();
//配置自定义的message转换器
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
messageConverters.add(new CustomMappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
//配置自定义的interceptor拦截器
List<ClientHttpRequestInterceptor> interceptors=new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new HeadClientHttpRequestInterceptor());
interceptors.add(new TrackLogClientHttpRequestInterceptor());
restTemplate.setInterceptors(interceptors);
//配置自定义的异常处理
restTemplate.setErrorHandler(new CustomResponseErrorHandler());
restTemplate.setRequestFactory(simleClientHttpRequestFactory);
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory reqFactory= new SimpleClientHttpRequestFactory();
reqFactory.setConnectTimeout(restTemplateConnectionTimeout);
reqFactory.setReadTimeout(restTemplateReadTimeout);
return reqFactory;
}
}
复制代码
2.3。コンポーネント(カスタム例外ハンドラ、インターセプターインターセプター、メッセージコンバータ)
カスタムinterceptor
インターセプタを達成するためClientHttpRequestInterceptor
のインタフェースを
- カスタム
TrackLogClientHttpRequestInterceptor
レコードresttemplate
のrequest
とresponse
情報分析を追跡することができます。 - カスタム
HeadClientHttpRequestInterceptor
、パラメータ設定要求ヘッダー。APIは、さまざまなリクエストを送信するために、多くの要求は、類似または同一のHTTPヘッダーを使用する必要があります。あなたがそれぞれの前にリクエストを考える場合はHeader
塗りつぶしHttpEntity/RequestEntity
、このようなコードは、むしろ冗長と思われるあなたは、統一されたインターセプタを設定することができます。
TrackLogClientHttpRequestInterceptor:
/**
* @Auther: ccww
* @Date: 2019/10/25 22:48,记录resttemplate访问信息
* @Description: 记录resttemplate访问信息
*/
@Slf4j
public class TrackLogClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
trackRequest(request,body);
ClientHttpResponse httpResponse = execution.execute(request, body);
trackResponse(httpResponse);
return httpResponse;
}
private void trackResponse(ClientHttpResponse httpResponse)throws IOException {
log.info("============================response begin==========================================");
log.info("Status code : {}", httpResponse.getStatusCode());
log.info("Status text : {}", httpResponse.getStatusText());
log.info("Headers : {}", httpResponse.getHeaders());
log.info("=======================response end=================================================");
}
private void trackRequest(HttpRequest request, byte[] body)throws UnsupportedEncodingException {
log.info("======= request begin ========");
log.info("uri : {}", request.getURI());
log.info("method : {}", request.getMethod());
log.info("headers : {}", request.getHeaders());
log.info("request body : {}", new String(body, "UTF-8"));
log.info("======= request end ========");
}
}
复制代码
HeadClientHttpRequestInterceptor:
@Slf4j
public class HeadClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
log.info("#####head handle########");
HttpHeaders headers = httpRequest.getHeaders();
headers.add("Accept", "application/json");
headers.add("Accept-Encoding", "gzip");
headers.add("Content-Encoding", "UTF-8");
headers.add("Content-Type", "application/json; charset=UTF-8");
ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, bytes);
HttpHeaders headersResponse = response.getHeaders();
headersResponse.add("Accept", "application/json");
return response;
}
}
复制代码
カスタム例外ハンドラ、継承DefaultResponseErrorHandler
または実装ResponseErrorHandler
インタフェース:
- カスタム実装
ErrorHandler
のアイデアは、応答メッセージの本文に応じて、対応する例外処理戦略、その他の異常の親であるDefaultResponseErrorHandler
処理のために。 - カスタム
CustomResponseErrorHandler
30X例外処理を行って
CustomResponseErrorHandler:
/**
* @Auther: Ccww
* @Date: 2019/10/28 17:00
* @Description: 30X的异常处理
*/
@Slf4j
public class CustomResponseErrorHandler extends DefaultResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = response.getStatusCode();
if(statusCode.is3xxRedirection()){
return true;
}
return super.hasError(response);
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
HttpStatus statusCode = response.getStatusCode();
if(statusCode.is3xxRedirection()){
log.info("########30X错误,需要重定向!##########");
return;
}
super.handleError(response);
}
}
复制代码
カスタムメッセージ改質器
/**
* @Auther: Ccww
* @Date: 2019/10/29 21:15
* @Description: 将Content-Type:"text/html"转换为Map类型格式
*/
public class CustomMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
public CustomMappingJackson2HttpMessageConverter() {
List<MediaType> mediaTypes = new ArrayList<MediaType>();
mediaTypes.add(MediaType.TEXT_PLAIN);
mediaTypes.add(MediaType.TEXT_HTML); //加入text/html类型的支持
setSupportedMediaTypes(mediaTypes);// tag6
}
}
复制代码
最後に、公共は、一緒になって、研究[番号] Ccwwノート心配であってもよいです。プラスグループ、毎日ビデオコレクションを学ぶだけでなく、乾燥品を共有することになります!