欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于遠(yuǎn)程調(diào)用RestTemplate的使用避坑指南

 更新時(shí)間:2021年10月28日 10:15:47   作者:河邊放牛娃  
這篇文章主要介紹了關(guān)于遠(yuǎn)程調(diào)用RestTemplate的使用避坑指南,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、前言介紹

RestTemplate是Spring中用于遠(yuǎn)程接口調(diào)用的工具類,它是Apache的HttpClient的模板封裝,使用起來(lái)非常方便,本文將講述這兩天自己在使用RestTemplate過(guò)程中遇到的問(wèn)題,當(dāng)然這些問(wèn)題也是由于自己對(duì)RestTemplate工具類了解不夠全面不夠透徹造成的,希望自己遇到的這些問(wèn)題能為大家提前避雷或是遇到類似問(wèn)題時(shí)的一個(gè)解決參考。

二、 問(wèn)題記錄

1. 慎!【url參數(shù)中有json字符串】

在使用RestTemplate進(jìn)行遠(yuǎn)程接口調(diào)用時(shí),如果url拼接參數(shù)中json字符串時(shí)一定要小心,使用場(chǎng)景如下:利用restTemplate調(diào)用user的查詢信息接口,url中的一個(gè)參數(shù)user為json字符串格式{\"user\":\"xiaoming,\"age\":"12"}

  // JSON參數(shù)
        Map<String, String> paramMap = new HashMap<>(8);
        paramMap.put("name","xiaoming");
        paramMap.put("age","12");
        String paramJsonStr = JSONObject.toJSONString(paramMap);
 
        // 實(shí)際參數(shù) url = "http://localhost:8080/api/user?user={\"name\":\"xiaoming\",\"age\":\"12\"}&country=china";
        String url = "http://localhost:8080/api/user?user=" + paramJsonStr + "&country=china";
        RestTemplate restTemplate = new RestTemplate();
        // 調(diào)用出錯(cuò)
        Object execute = restTemplate.execute(url, HttpMethod.GET, null, null);

此時(shí)當(dāng)我們運(yùn)行程序時(shí)會(huì)拋出以下錯(cuò)誤:

錯(cuò)誤意思大概是沒(méi)有足夠可用的變量值來(lái)填充擴(kuò)展 'name',這是什么鬼意思,別著急讓我們跟跟代碼看看異常拋出的位置,最終定位如下,在創(chuàng)建URI過(guò)程中調(diào)用了 UriComponents.expandUriComponent()方法拋出異常:

這段代碼的作用其實(shí)就是通過(guò)NAMES_PATERN規(guī)則匹配到相應(yīng)字符串然后利用 uriVariables.getValue(varibaleName)進(jìn)行替換,再看看NAMES_PATERN的值就是用來(lái)匹配{}中的字符串內(nèi)容的

private static final Pattern NAMES_PATTERN = Pattern.compile(\\{([^/]+?)\\});

問(wèn)題分析到這兒相信大家應(yīng)該也明白了RestTemplate在創(chuàng)建URI時(shí)會(huì)進(jìn)行{param}占位替換,這個(gè)規(guī)則在文本輸出時(shí)應(yīng)用比較多,如日志打印和控制臺(tái)打印中常有使用:

   String value = "test";
   logger.info("占位參數(shù){}",value);

解決辦法:

找到原因了,那么我們應(yīng)當(dāng)如何解決呢,既然RestTemplate在處理url時(shí)會(huì)進(jìn)行{}變量替換,那它理應(yīng)提供相應(yīng)的接口調(diào)用,查看RestTemplate源碼它提供了多個(gè)exchange重載方法,其中多個(gè)方法都有uriVariables參數(shù),如下所示:

    public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
        URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
        return this.doExecute(expanded, method, requestCallback, responseExtractor);
    }

那么我們將url稍微修改即可解決問(wèn)題:

2. 慎!【url參數(shù)中有經(jīng)過(guò)URLEncode的字符串】

其實(shí)在遇到第一個(gè)坑時(shí),我并沒(méi)有采用上面給出的解決方式,而是想著將Json字符串經(jīng)過(guò)URLEncode編碼后在拼接到url后面,不就沒(méi)有{}符號(hào)了,不就可以完美解決問(wèn)題了,心里想著就美滋滋,那讓我們來(lái)試一把吧:

      // JSON參數(shù)
        Map<String, String> paramMap = new HashMap<>(8);
        paramMap.put("name","xiaoming");
        paramMap.put("age","12");
        String paramJsonStr = JSONObject.toJSONString(paramMap);
 
        // 實(shí)際參數(shù) url = "http://localhost:8080/api/user?user=%7B%22name%22%3A%22xiaoming%22%2C%22age%22%3A%2212%22%7D&country=china";
        String encode = URLEncoder.encode(paramJsonStr, "utf-8");
        String url = "http://localhost:8080/api/user?user="+encode+"&country=china";
        System.out.println(url);
        RestTemplate restTemplate = new RestTemplate();
        Object execute = restTemplate.execute(url, HttpMethod.GET, null, null,paramJsonStr);

json字符串經(jīng)過(guò)編碼后已經(jīng)沒(méi)有{}符號(hào)了,也能夠成功調(diào)用接口,但是接口提供方無(wú)情的返回了錯(cuò)誤:參數(shù)無(wú)法反序列化。聽這口氣肯定也是這json串的原因,趕緊用Postman試一試:

神奇的一幕出現(xiàn)了,居然成功了! Postman方式調(diào)用和RestTemplate調(diào)用有什么不一樣,為什么postman行,restTemplate不行?趕緊查看服務(wù)器日志看看兩種方式接收到的參數(shù)有和不一樣:

1. Postman方式服務(wù)器接收到的url:

"http://localhost:8080/api/user?user=%7B%22name%22%3A%22xiaoming%22%2C%22age%22%3A%2212%22%7D&country=china"

2. RestTemplate方式服務(wù)器接收到的url

"http://localhost:8080/api/user?user=%257B%2522name%2522%3A%2522xiaoming%2522%2C%2522age%2522%253A%252212%2522%257D&country=china"

restTemplate居然在每個(gè)百分號(hào)%后面都擅自加了25這個(gè)數(shù)字,難怪服務(wù)端沒(méi)法解析,它為什么要這么做?難道是restTemplate的url處理bug?讓我們跟一跟代碼看個(gè)究竟:

詳細(xì)調(diào)用層次就不貼了,簡(jiǎn)單來(lái)說(shuō)就是RestTemplate在處理url時(shí)會(huì)對(duì)url參數(shù)進(jìn)行再編碼,也就是會(huì)對(duì)url中的特殊字符進(jìn)行轉(zhuǎn)義,如%號(hào)會(huì)被轉(zhuǎn)義為%25,所以傳給服務(wù)端的url就被改變了,具體url特殊字符轉(zhuǎn)義知識(shí)請(qǐng)查看這篇文章

既然知道了原因,那么我們應(yīng)該如何解決呢?

解決方案:

RestTemplate中的URI對(duì)象是通過(guò)UriTemplateHandler生成的,所以我們只需要利用java.net包中的URI自己構(gòu)建URI對(duì)象傳給RestTemplate即可,這樣url中的特殊字符就不會(huì)被轉(zhuǎn)義了:

3. 慎!【url參數(shù)中存在特殊字符】 --- 針對(duì)HttpClient

前面兩個(gè)坑然我對(duì)RestTemplate有點(diǎn)望而生畏了,既然RestTemplate這么多坑,那好咋們換回老家伙apache家族的HttpClient,本以為可以一切順利,沒(méi)成想一坑接著一坑啊!!!

先看看調(diào)用場(chǎng)景:按照出生時(shí)間去查詢用戶信息

調(diào)用請(qǐng)求都還沒(méi)發(fā)出就無(wú)情報(bào)錯(cuò)了:

通過(guò)異常信息可以容易知道在創(chuàng)建URL對(duì)象時(shí)url參數(shù)索引位置50處有非法字符,而這個(gè)字符剛好就是時(shí)間參數(shù)中的空格!,跟蹤代碼異常發(fā)生位置發(fā)現(xiàn)下面一段注釋,大意就是不允許url中有特殊字符存在,看了本文第二個(gè)坑的應(yīng)該已經(jīng)明白u(yù)rl中特殊字符為什么需要進(jìn)行轉(zhuǎn)義了,這里就不詳細(xì)敘述,至此解決方案就呼之欲出了。

解決方案:

需要對(duì)參數(shù)中的特殊字符進(jìn)行轉(zhuǎn)義:

1. 直接特殊字符替換

2. 利用google的工具包UrlEscapers(可以處理url、xml、html中的特殊字符)

maven依賴

 <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
    <dependency>
      <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>28.1-jre</version>
    </dependency>

使用方式:UrlEscapers可以對(duì)路徑、參數(shù)、片段進(jìn)行處理,提供了 path,parameter,fragment三個(gè)部分的Escape實(shí)例

分別調(diào)用UrlEscapers類的以下方法獲?。?/p>

  • urlFormParameterEscaper()
  • urlPathSegmentEscaper()
  • urlFragmentEscaper()

總結(jié)

本次三個(gè)案例本人覺(jué)得還是具有典型性,由于平時(shí)發(fā)起請(qǐng)求大多通過(guò)瀏覽器或者是postman這類的http模擬工具進(jìn)行,而瀏覽器和模擬工具在內(nèi)部會(huì)對(duì)請(qǐng)求url和參數(shù)進(jìn)行一定處理,例如編碼和轉(zhuǎn)義,所以平時(shí)對(duì)這塊關(guān)注不多,而當(dāng)我們?cè)趕erver端自我構(gòu)建http請(qǐng)求進(jìn)行遠(yuǎn)程調(diào)用時(shí)這類問(wèn)題就需要我們特別注意,稍有不慎就會(huì)掉入坑中,還有一點(diǎn)感悟在使用一個(gè)工具類時(shí)應(yīng)當(dāng)先大致閱讀一下工具類提供了哪些方法,做到心中有數(shù)使用時(shí)就會(huì)少走很多彎路。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • IDEA 如何導(dǎo)入別人的javaweb項(xiàng)目進(jìn)行部署

    IDEA 如何導(dǎo)入別人的javaweb項(xiàng)目進(jìn)行部署

    這篇文章主要介紹了IDEA 如何導(dǎo)入別人的javaweb項(xiàng)目進(jìn)行部署,本文給大家分享我的詳細(xì)部署過(guò)程及遇到問(wèn)題解決方法,需要的朋友可以參考下
    2023-03-03
  • springcloud gateway自定義斷言規(guī)則詳解,以后綴結(jié)尾進(jìn)行路由

    springcloud gateway自定義斷言規(guī)則詳解,以后綴結(jié)尾進(jìn)行路由

    這篇文章主要介紹了springcloud gateway自定義斷言規(guī)則詳解,以后綴結(jié)尾進(jìn)行路由,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • java壓縮zip文件中文亂碼問(wèn)題解決方法

    java壓縮zip文件中文亂碼問(wèn)題解決方法

    這篇文章主要介紹了java壓縮zip文件中文亂碼問(wèn)題的解決方法,需要的朋友可以參考下
    2014-07-07
  • IDEA提高開發(fā)效率的7個(gè)插件(推薦)

    IDEA提高開發(fā)效率的7個(gè)插件(推薦)

    這篇文章主要介紹了IDEA提高開發(fā)效率的7個(gè)插件(推薦),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • SpringBoot結(jié)合JSR303對(duì)前端數(shù)據(jù)進(jìn)行校驗(yàn)的示例代碼

    SpringBoot結(jié)合JSR303對(duì)前端數(shù)據(jù)進(jìn)行校驗(yàn)的示例代碼

    這篇文章主要介紹了SpringBoot結(jié)合JSR303對(duì)前端數(shù)據(jù)進(jìn)行校驗(yàn)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java通過(guò)PDF模板填寫PDF表單

    java通過(guò)PDF模板填寫PDF表單

    這篇文章主要為大家詳細(xì)介紹了java通過(guò)PDF模板填寫PDF表單,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Java的NIO之通道channel詳解

    Java的NIO之通道channel詳解

    這篇文章主要介紹了Java的NIO之通道channel詳解,通道channel由java.nio.channels 包定義的,Channel 表示IO源與目標(biāo)打開的連接,Channel類類似于傳統(tǒng)的"流",只不過(guò)Channel本身不能直接訪問(wèn)數(shù)據(jù),Channel只能與Buffer進(jìn)行交互,需要的朋友可以參考下
    2023-10-10
  • Java中轉(zhuǎn)換器設(shè)計(jì)模式深入講解

    Java中轉(zhuǎn)換器設(shè)計(jì)模式深入講解

    這篇文章主要給大家介紹了關(guān)于Java中轉(zhuǎn)換器設(shè)計(jì)模式的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Servlet開發(fā)JavaWeb工程示例詳解

    Servlet開發(fā)JavaWeb工程示例詳解

    這篇文章主要介紹了Servlet開發(fā)JavaWeb工程示例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • JavaWeb文件上傳入門教程

    JavaWeb文件上傳入門教程

    這篇文章主要為大家詳細(xì)介紹了JavaWeb文件上傳入門教程,分析了文件上傳原理、介紹了第三方上傳組件,感興趣的小伙伴們可以參考一下
    2016-06-06

最新評(píng)論