最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于restTemplate遇到的編碼問(wèn)題及解決

 更新時(shí)間:2021年10月28日 10:44:28   作者:zhuxingKevin  
這篇文章主要介紹了restTemplate遇到的編碼問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

背景

之前用restTemplate做網(wǎng)絡(luò)間的請(qǐng)求,沒(méi)遇到過(guò)問(wèn)題。今天先是出現(xiàn)了中文亂碼的問(wèn)題,而后又出現(xiàn)了特殊字符丟失的問(wèn)題,于是查找資料及翻看源碼,將問(wèn)題解決也順便記錄下。

問(wèn)題一:中文亂碼

描述

在創(chuàng)建課件時(shí),使用GET方法傳遞類型和標(biāo)題兩個(gè)參數(shù)到服務(wù)器,服務(wù)器返回一個(gè)課件編號(hào)。類型是固定數(shù)字1,不存在問(wèn)題,而標(biāo)題則是用戶輸入字符串,也就是任意字符串。發(fā)現(xiàn)輸入漢字的時(shí)候,結(jié)果網(wǎng)絡(luò)傳輸后在服務(wù)器端出現(xiàn)了亂碼。輸入標(biāo)題為:開(kāi)發(fā)測(cè)試001,結(jié)果在服務(wù)器上接收到的為:%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001。

分析

出現(xiàn)編碼問(wèn)題,那肯定是對(duì)涉及到這個(gè)標(biāo)題的編碼的位置出現(xiàn)了問(wèn)題,于是查找涉及到的代碼位置:

public String createPptSlide(String title) {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(host + PPT_SLIDE_INSERT);
        builder.queryParam("businessLineId", PPT_BUSINESS_LINE_ID);
        builder.queryParam("slideTitle", title);
        String url = builder.toUriString();
        restTemplate.getForEntity(url, JSONObject.class);
}

此處的String url已經(jīng)是編碼過(guò)了的http://xxx.com/slide/insertEmptySlide?businessLineId=1&slideTitle=%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001

于是繼續(xù)追蹤getForEntity方法,在執(zhí)行doExecute方法前,構(gòu)造URI時(shí)又進(jìn)行了一次編碼,如下:

@Override
    public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> urlVariables)
            throws RestClientException {
        RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
        ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
        return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
    }
public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback,
            ResponseExtractor<T> responseExtractor, Map<String, ?> urlVariables) throws RestClientException {
        URI expanded = new UriTemplate(url).expand(urlVariables);
        return doExecute(expanded, method, requestCallback, responseExtractor);
}
public URI expand(Map<String, ?> uriVariables) {
        UriComponents expandedComponents = this.uriComponents.expand(uriVariables);
        UriComponents encodedComponents = expandedComponents.encode();
        return encodedComponents.toUri();
}

結(jié)論

在程序構(gòu)建url時(shí),程序代碼已經(jīng)對(duì)title進(jìn)行了一次編碼,,傳入restTemplate后,restTemplate框架本身又會(huì)對(duì)其做一次編碼,最后服務(wù)器接收到的參數(shù)其實(shí)是做了兩次編碼,導(dǎo)致解碼后還是亂碼。

第一次編碼:%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001

第二次編碼:%25E5%25BC%2580%25E5%258F%2591%25E6%25B5%258B%25E8%25AF%2595001

解碼后:%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001

側(cè)面論證:

這里的編碼是URLencode,這個(gè)編碼簡(jiǎn)單來(lái)講就是:將非字母數(shù)字字符都將被替換成百分號(hào)(%)后跟兩位十六進(jìn)制數(shù)??梢钥吹竭@一串的亂碼%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001很像urlencode后的結(jié)果,解碼后發(fā)現(xiàn)果真是這樣。

image.png

方案

傳入url前不對(duì)title進(jìn)行編碼,直接拼接原始的參數(shù),然后傳入到restTemplate,讓restTemplate框架來(lái)進(jìn)行編碼。這樣解決了中文亂碼的問(wèn)題,如下:

UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(host + PPT_SLIDE_INSERT);
        builder.queryParam("businessLineId", PPT_BUSINESS_LINE_ID);
        String url = builder.toUriString();
        // 不能 encode 參數(shù)
        if (StringUtils.isNotBlank(title)) {
            url = url + "&slideTitle=" + title;
        }
        restTemplate.getForEntity(url, JSONObject.class);
}

總結(jié)

項(xiàng)目中使用restTemplate的地方,在傳給restTemplate框架url的時(shí)候都進(jìn)行了一次編碼,于是自己也照搬過(guò)來(lái),殊不知restTemplate框架本身就會(huì)對(duì)url進(jìn)行編碼。

其實(shí)從一個(gè)框架設(shè)計(jì)者的角度上將,urlencode是每個(gè)請(qǐng)求都會(huì)用到的,很順利的可以想到框架會(huì)包含這個(gè)urlencode功能,不需要編程人員將參數(shù)urlencode。

問(wèn)題二:特殊字符串丟失

描述

在使用restTemplate傳遞課件標(biāo)題的時(shí)候,發(fā)現(xiàn)有一些特殊字符串有數(shù)據(jù)丟失問(wèn)題,例如傳遞課件標(biāo)題:開(kāi)發(fā)測(cè)試001&aaa,接收方接到的是:開(kāi)發(fā)測(cè)試001,后面跟的&aaa字符丟失了。

分析

再一次懷疑是restTemplate里面自帶的編碼導(dǎo)致的問(wèn)題,于是對(duì)比了直接使用urlencode與使用restTemplate編碼的結(jié)果,如下表:

urlencode

%e5%bc%80%e5%8f%91%e6%b5%8b%e8%af%95001%26aaa

restTemplate

%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001&aaa

明顯可以發(fā)現(xiàn)restTemplate對(duì)特殊字符“&”沒(méi)有進(jìn)行url編碼,導(dǎo)致最后構(gòu)建成的url是這樣的:

http://xxx.com/slide/insertEmptySlide?businessLineId=1&slideTitle=%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001&aaa

這樣就會(huì)把&aaa中的aaa當(dāng)成get請(qǐng)求中的一個(gè)參數(shù)來(lái)看待,從而得到的title只為:%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001,導(dǎo)致丟失了&aaa字符,接收方解析也只能得到標(biāo)題為:開(kāi)發(fā)測(cè)試001。

結(jié)論

restTemplate在進(jìn)行url編碼的時(shí)候,不會(huì)對(duì)某些特殊字符的編碼,例如&。

方案

既然restTemplate會(huì)忽略掉某些特殊字符的url編碼,那么我們就索性不用restTemplate編碼,直接自己編碼好,跳過(guò)restTemplate的編碼,實(shí)現(xiàn)方案為:

public String createPptSlide(String title) {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(host + PPT_SLIDE_INSERT);
        builder.queryParam("businessLineId", PPT_BUSINESS_LINE_ID);
        builder.queryParam("slideTitle", title);
        URI uri = builder.build().encode().toUri();
        restTemplate.getForEntity(uri, JSONObject.class);
}

(ps:傳String的url,restTemplate都會(huì)再一次進(jìn)行編碼,而直接傳URI可以跳過(guò)restTemplate的編碼)

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

相關(guān)文章

  • 解決Springboot中Feignclient調(diào)用時(shí)版本問(wèn)題

    解決Springboot中Feignclient調(diào)用時(shí)版本問(wèn)題

    這篇文章主要介紹了解決Springboot中Feign?client調(diào)用時(shí)版本問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java利用反射獲取object的屬性和值代碼示例

    Java利用反射獲取object的屬性和值代碼示例

    這篇文章主要介紹了Java利用反射獲取object的屬性和值代碼示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12
  • springcloud feign傳輸List的坑及解決

    springcloud feign傳輸List的坑及解決

    這篇文章主要介紹了springcloud feign傳輸List的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Spring Boot示例代碼整合Redis詳解

    Spring Boot示例代碼整合Redis詳解

    SpringBoot對(duì)常用的數(shù)據(jù)庫(kù)支持外,對(duì)NoSQL 數(shù)據(jù)庫(kù)也進(jìn)行了封裝自動(dòng)化,下面這篇文章主要給大家介紹了關(guān)于springboot使用redis的詳細(xì)步驟,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Mybatis使用on duplicate key update的實(shí)現(xiàn)操作

    Mybatis使用on duplicate key update的實(shí)現(xiàn)操作

    本文主要介紹了Mybatis使用on duplicate key update的實(shí)現(xiàn)操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目

    Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目

    本篇文章主要介紹了Maven學(xué)習(xí)教程之搭建多模塊企業(yè)級(jí)項(xiàng)目 ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Java中Jackson快速入門(mén)

    Java中Jackson快速入門(mén)

    這篇文章主要介紹了Java中Jackson快速入門(mén),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重復(fù)讀取配置文件的方法

    Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重復(fù)讀取配置文

    這篇文章主要介紹了Java使用ByteArrayOutputStream 和 ByteArrayInputStream 避免重復(fù)讀取配置文件的方法,需要的朋友可以參考下
    2015-12-12
  • MyBatis-Plus樂(lè)觀鎖插件的用法小結(jié)

    MyBatis-Plus樂(lè)觀鎖插件的用法小結(jié)

    樂(lè)觀鎖很樂(lè)觀,對(duì)任何事情都保持著一個(gè)樂(lè)觀的態(tài)度,認(rèn)為別人不會(huì)修改數(shù)據(jù),所以不會(huì)上鎖,只是在更新數(shù)據(jù)的時(shí)候,去判斷這條數(shù)據(jù)有沒(méi)有被別人修改過(guò),這篇文章主要介紹了MyBatis-Plus樂(lè)觀鎖插件的用法,需要的朋友可以參考下
    2022-08-08
  • SpringBoot整合Druid實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池和監(jiān)控

    SpringBoot整合Druid實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池和監(jiān)控

    Druid是Java語(yǔ)言中使用的比較多的數(shù)據(jù)庫(kù)連接池。Druid還提供了強(qiáng)大的監(jiān)控和擴(kuò)展功能。面將介紹SpringBoot整合Druid實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接池和監(jiān)控功能,感興趣的可以了解一下
    2021-08-08

最新評(píng)論

明溪县| 即墨市| 全南县| 同心县| 嘉荫县| 牟定县| 丰镇市| 湖州市| 崇礼县| 宜春市| 田东县| 石景山区| 河池市| 出国| 宁阳县| 米林县| 潼南县| 交口县| 北票市| 开化县| 石门县| 道孚县| 大田县| 泾川县| 永丰县| 高台县| 汝州市| 元阳县| 闸北区| 金塔县| 盐山县| 麻城市| 砚山县| 浪卡子县| 绥化市| 平陆县| 于田县| 拜泉县| 胶州市| 霞浦县| 宁明县|