restTemplate使用和踩坑總結

日常工作中肯定會遇到服務之間的調用,尤其是現在都是微服務的架構,所以總結一下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}*/@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();}}}
復制代碼

我們一般都是用的restTepmlate的exchange方法,這個方法比較靈活,可以接受可變參數,重載方法也有很多。 當然 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的時候,當你的call沒有成功返回200的時候,比如返回400 500之類的,restTemplate里面有一個DefaultResponseErrorHandler,他會自動攔截住這些httpstatus 為400 500的response然后給你拋出一個異常。這就意味著,當你也想拿到帶有錯誤信息的response的時候,他不會給你!它會給你拋出exception并且只是給你返回一個簡單的類似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 {@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);}}}復制代碼

然后在初始化restTemplate的時候調用setErrorHandle方法就可以了。

restTemplate.setErrorHandler(YourErrorHandle).
復制代碼

至于方式一這里不提了。

導入證書

有的時候當我們調用對方的server時,基于https 的協議是需要導入證書的,那我們該怎么把證書融入到restTemplate中呢?(又一個坑)

@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;}
復制代碼

相當于重新給RequestFactory值,構造一個已經帶有ssl證書的factory給他。

這里注意兩個地方:

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

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

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

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

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

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

本地調試證書導入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詳細資料,可以參考: juejin.im/post/5b88b1… www.zifangsky.cn/1221.html

或者其他掘金好文。

轉載于:https://juejin.im/post/5cb96e84e51d456e5d3dac38

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387822.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387822.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387822.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常見編碼總結

本文總結自&#xff1a;https://blog.csdn.net/zmx729618/article/details/51821024 1. ISO 8859-1 字節數&#xff1a;1 范圍&#xff1a;0-255&#xff08;編碼范圍是0x00-0xFF&#xff09;&#xff0c;其中0x00-0x7F之間完全和ASCII一致&#xff08;ASCII是7位編碼&#xff…

啟動一個Java進程

windows版本 startup.bat -------------------------------------------------------- rem --------------------------------------------------------------------------- rem Start SMS Server by zhangjin rem --------------------------------------------------------…

Flask框架從入門到精通之參數配置(二)

知識點&#xff1a; 1、參數配置 一、概況 上一篇我們已經把Flask第一個程序運行起來了&#xff0c;那么這一篇主要講一下Flask參數的配置。 二、配置參數 Flask參數配置方式有很多種&#xff0c;每一種都可以達到結果&#xff0c;在合適的場景選擇合適的配置方式。 配置文件 在…

BP神經網絡python簡單實現

BP神經網絡的原理在網上有很詳細的說明&#xff0c;這里就不打算細說&#xff0c;這篇文章主要簡單的方式設計及實現BP神經網絡&#xff0c;并簡單測試下在恒等計算&#xff08;編碼&#xff09;作測試。 BP神經網絡模型圖如下 BP神經網絡基本思想 BP神經網絡學習過程由信息的…

golang的reflection(轉)(一)

2019獨角獸企業重金招聘Python工程師標準>>> 反射reflection 可以大大提高程序的靈活性&#xff0c;使得interface{}有更大的發揮余地反射可以使用TypeOf和ValueOf函數從接口中獲取目標對象信息反射會將匿名字段作為獨立字段&#xff08;匿名字段的本質&#xff09;…

idea教程--Maven 骨架介紹

簡單的說&#xff0c;Archetype是Maven工程的模板工具包。一個Archetype定義了要做的相同類型事情的初始樣式或模型。這個名稱給我們提供來了一個一致的生成Maven工程的方式。Archetype會幫助作者給用戶創建Maven工程模板&#xff0c;并給用戶提供生成相關工程模板版本的參數化…

datatables.js 簡單使用--多選框和服務器端分頁

說明&#xff1a;datatables是一款jQuery表格插件。感覺EasyUI的datagrid更易用 內容&#xff1a;多選框和服務器端分頁 緣由&#xff1a;寫這篇博客的原因是datatables的文檔寫的不怎么樣&#xff0c;找東西很麻煩 環境&#xff1a;asp.net mvc , vs2015sqlserver2012 顯示效…

python異常(高級) Exception

異常(高級) Exception 異常回顧:     try-except 語句 捕獲(接收)異常通知,把異常流程變為正常流程     try-finally 語句 執行必須要執行的語句.     raise 語句 發送異常通知,同時進入異常流程     assert 語句 發送AssertionError異常     with 語句 wi…

反射賦值

目前例子為NPOI Excel導入 入庫時調用 var file file1.PostedFile.InputStream;var fileExt System.IO.Path.GetExtension(file1.FileName);IWorkbook workbook;if (fileExt ".xlsx")workbook new XSSFWorkbook(file);elseworkbook new HSSFWorkbook(file);DB.D…

基于PCA(主成分分析)的人臉識別

代碼下載&#xff1a;基于PCA&#xff08;主成分分析&#xff09;的人臉識別 人臉識別是一個有監督學習過程&#xff0c;首先利用訓練集構造一個人臉模型&#xff0c;然后將測試集與訓練集進行匹配&#xff0c;找到與之對應的訓練集頭像。最容易的方式是直接利用歐式距離計算測…

從BMW Vision iNEXT 看寶馬如何進軍自動駕駛

安全很重要&#xff0c;空間也要很大&#xff0c;砍掉大量物理按鍵&#xff0c;內飾材料要環保&#xff0c;還要提供自動和主動兩套駕駛方案。這些描述僅是BMW Vision iNEXT&#xff08;下稱Vision iNEXT&#xff09;概念車的設計之冰山一角。 一款概念車當然無法完全代表未來…

CSS浮動(二)---Float

重新認識float 2.1. 誤解和“誤用” 既然提到“誤用”&#xff0c;各位看官就此想想&#xff0c;自己平日是怎么使用float的&#xff1f;另外&#xff0c;既然“誤用”加了引號&#xff0c;就說明這樣的使用并不是真正的誤用&#xff0c;而是誤打誤撞使用之后&#xff0c;帶…

Hadoop0.20.2版本在Ubuntu下安裝和配置

1、安裝JDK   &#xff08;1&#xff09;下載安裝JDK&#xff1a;確保計算機聯網之后命令行輸入下面命令安裝JDK   sudo apt-get install sun-java6-jdk   &#xff08;2&#xff09;配置計算機Java環境&#xff1a;打開/etc/profile&#xff0c;在文件最后輸入下面內容 …

云原生生態周報 Vol. 2

業界要聞 Kubernetes External Secrets 近日&#xff0c;世界上最大的域名托管公司 Godaddy公司&#xff0c;正式宣布并詳細解讀了其開源的K8s外部 Secrets 管理項目&#xff1a; Kubernetes External Secrets&#xff0c;簡稱KES。這個項目定義了ExternalSecrets API&#xff…

centos 7新機使用前操作

關閉防火墻 systemctl stop firewalld&#xff08;停服務&#xff09; systemctl status firewalld&#xff08;看狀態&#xff09; systemctl disable firewalld.service &#xff08;永久關閉&#xff09; selinux getenforce&#xff08;查狀態&#xff09; vi /etc/selinux…

ubuntu10.04+hadoop0.20.2平臺配置(完全分布式模式)

配置環境及有關工具&#xff1a;ubuntu10.04 、hadoop0.20.2 、 jdk1.6.0_29 我們的機器有三臺&#xff0c;一臺當作namenode、兩臺當作datanode&#xff1a; namenode&#xff1a;IP:192.168.0.25、機器名&#xff1a;kiddenzj &#xff08;這里的機器名要注意&#xff1a;機…

成佛、遠不止渡滄海

地之及東南&#xff0c;有一海&#xff0c;稱為“滄海”。滄海對面&#xff0c;就是仙家佛地。凡是能渡過滄海到達彼岸的人&#xff0c;就能立地成佛&#xff0c;修成正果。 于是&#xff0c;許許多多的人千里迢迢趕來&#xff0c;或乘帆船&#xff0c;或乘木筏&#xff0c;紛紛…

軟件架構演進

傳統架構到分布式架構詳解 軟件架構演進軟件架構的發展經歷了從單體架構、垂直架構、SOA架構到微服務架構的過程&#xff0c;博客里寫到了這四種架構的特點以及優缺點分析&#xff0c;個人學習之用&#xff0c;僅供參考&#xff01; 1.1.1 單體架構 特點&#xff1a;1、所有的…

hadoop0.20.0第一個例子

這是Hadoop學習全程記錄第2篇&#xff0c;在這篇里我將介紹一下如何在Eclipse下寫第一個MapReduce程序。 新說明一下我的開發環境&#xff1a; 操作系統&#xff1a;在windows下使用wubi安裝了ubuntu 10.10 hadoop版本&#xff1a;hadoop-0.20.2.tar.gz Eclipse版本&…

IDEA 修改JavaWeb的訪問路徑

問題描述 對于我這個剛剛使用IDEA不久的新手來說&#xff0c;能夠正常運行就不錯了,不過到了后面&#xff0c;可能會覺得IDEA給你分配的默認訪問路徑很不順手&#xff0c;比如訪問的時候需要通過: http://localhost:8080/web_war_exploded/ 來訪問&#xff0c;對于web_w…