日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

restTemplate使用和踩坑总结

發(fā)布時(shí)間:2023/11/29 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 restTemplate使用和踩坑总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

日常工作中肯定會遇到服務(wù)之間的調(diào)用,尤其是現(xiàn)在都是微服務(wù)的架構(gòu),所以總結(jié)一下restTemplate的最常用的用法以及自己踩過的坑。

restTemplate的使用

restTemplate底層調(diào)用的是Execute方法,而Execute底層調(diào)用的是doExecute,它是基于http協(xié)議的,底層還是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}*/@Nullableprotected <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();}}} 復(fù)制代碼

我們一般都是用的restTepmlate的exchange方法,這個(gè)方法比較靈活,可以接受可變參數(shù),重載方法也有很多。 當(dāng)然 restTemplate還有其他很多方法,而且遵循restFul風(fēng)格,像PUT POST GET PATCH DELETE 等都有對應(yīng)的方法,按需使用。這里就不貼源碼了。

然后就貼一個(gè)使用案例代碼上來:

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());}} 復(fù)制代碼

踩坑大道

這里就要說一下我遇到的坑了。 在使用restTemplate的時(shí)候,當(dāng)你的call沒有成功返回200的時(shí)候,比如返回400 500之類的,restTemplate里面有一個(gè)DefaultResponseErrorHandler,他會自動攔截住這些httpstatus 為400 500的response然后給你拋出一個(gè)異常。這就意味著,當(dāng)你也想拿到帶有錯誤信息的response的時(shí)候,他不會給你!它會給你拋出exception并且只是給你返回一個(gè)簡單的類似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));}} 復(fù)制代碼

脫坑之計(jì)

遇到了坑就不要害怕,這個(gè)問題可以這么解決:

1.不用restTemplate去請求,可以采用httpClient底層去實(shí)現(xiàn)

2.重寫handleError方法,自定義ErrorHandle繼承DefaultResponseErrorHandler

在已經(jīng)寫完實(shí)現(xiàn)之后,我選擇方式2 : )

@Builder @Slf4j public class MyErrorHandle extends DefaultResponseErrorHandler {@Overridepublic 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);}}}復(fù)制代碼

然后在初始化restTemplate的時(shí)候調(diào)用setErrorHandle方法就可以了。

restTemplate.setErrorHandler(YourErrorHandle). 復(fù)制代碼

至于方式一這里不提了。

導(dǎo)入證書

有的時(shí)候當(dāng)我們調(diào)用對方的server時(shí),基于https 的協(xié)議是需要導(dǎo)入證書的,那我們該怎么把證書融入到restTemplate中呢?(又一個(gè)坑)

@Beanpublic 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;} 復(fù)制代碼

相當(dāng)于重新給RequestFactory值,構(gòu)造一個(gè)已經(jīng)帶有ssl證書的factory給他。

這里注意兩個(gè)地方:

SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); 復(fù)制代碼

這里有個(gè)參數(shù)是NoopHostnameVerifier.INSTANCE, 這里是可以無視ip的,也就是ip或者域名形式都可以。 (適用于對方給我提供證書和 ip地址,試了半天死活不通的情況。。)

第二個(gè)就是一個(gè)工具類的使用,我相信很多時(shí)候new file的時(shí)候很容易被路徑繞暈。

String workingDirectory = BeanUtility.getWorkingDirectory(); 復(fù)制代碼

這個(gè)工具類獲得的路徑不用你去擔(dān)心,只要你的jks文件和你的jar包同級就行。管他什么環(huán)境什么路徑,很方便。

貼上地址: github.com/AnsonCong/A…

本地調(diào)試證書導(dǎo)入jdk就行。

記錄下導(dǎo)入證書的方法:

keytool -import -alias {別名} -file {路徑\證書名}.cer -keystore "{jdk路徑\jre\lib\security\cacerts}" -storepass {password} -trustcacerts 復(fù)制代碼

刪除證書:

keytool -delete -alias {別名} -keystore "C:\Program Files\Java\jdk1.7.0_25\jre\lib\security\cacerts" -storepass {password} 復(fù)制代碼

查看所有安裝證書列表

keytool -list -v -keystore "C:\Users\1580977\Downloads\jdk1.8.0_101\jre\lib\security\cacerts" -storepass {password} >> C:\Desktop\abcd.txt 復(fù)制代碼

生成jks文件 (沒有默認(rèn)生存,有就導(dǎo)入)

keytool -import -alias {別名} -file {證書名}.cer -keystore {命名}.jks 復(fù)制代碼

最后

RestTemplate是Spring提供的用于訪問Rest服務(wù)的客戶端,RestTemplate提供了多種便捷訪問遠(yuǎn)程Http服務(wù)的方法,能夠大大提高客戶端的編寫效率。

更多restTemplate詳細(xì)資料,可以參考: juejin.im/post/5b88b1… www.zifangsky.cn/1221.html

或者其他掘金好文。

轉(zhuǎn)載于:https://juejin.im/post/5cb96e84e51d456e5d3dac38

總結(jié)

以上是生活随笔為你收集整理的restTemplate使用和踩坑总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。