一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 基于restTemplate遇到的編碼問題及解決

基于restTemplate遇到的編碼問題及解決

2022-03-04 00:44zhuxingKevin Java教程

這篇文章主要介紹了restTemplate遇到的編碼問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

背景

之前用restTemplate做網絡間的請求,沒遇到過問題。今天先是出現了中文亂碼的問題,而后又出現了特殊字符丟失的問題,于是查找資料及翻看源碼,將問題解決也順便記錄下。

問題一:中文亂碼

描述

在創建課件時,使用GET方法傳遞類型和標題兩個參數到服務器,服務器返回一個課件編號。類型是固定數字1,不存在問題,而標題則是用戶輸入字符串,也就是任意字符串。發現輸入漢字的時候,結果網絡傳輸后在服務器端出現了亂碼。輸入標題為:開發測試001,結果在服務器上接收到的為:%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001。

分析

出現編碼問題,那肯定是對涉及到這個標題的編碼的位置出現了問題,于是查找涉及到的代碼位置:

?
1
2
3
4
5
6
7
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已經是編碼過了的http://xxx.com/slide/insertEmptySlide?businessLineId=1&slideTitle=%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001

于是繼續追蹤getForEntity方法,在執行doExecute方法前,構造URI時又進行了一次編碼,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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();
}

結論

在程序構建url時,程序代碼已經對title進行了一次編碼,,傳入restTemplate后,restTemplate框架本身又會對其做一次編碼,最后服務器接收到的參數其實是做了兩次編碼,導致解碼后還是亂碼。

第一次編碼:%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

側面論證:

這里的編碼是URLencode,這個編碼簡單來講就是:將非字母數字字符都將被替換成百分號(%)后跟兩位十六進制數。可以看到這一串的亂碼%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001很像urlencode后的結果,解碼后發現果真是這樣。

基于restTemplate遇到的編碼問題及解決

方案

傳入url前不對title進行編碼,直接拼接原始的參數,然后傳入到restTemplate,讓restTemplate框架來進行編碼。這樣解決了中文亂碼的問題,如下:

?
1
2
3
4
5
6
7
8
9
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(host + PPT_SLIDE_INSERT);
        builder.queryParam("businessLineId", PPT_BUSINESS_LINE_ID);
        String url = builder.toUriString();
        // 不能 encode 參數
        if (StringUtils.isNotBlank(title)) {
            url = url + "&slideTitle=" + title;
        }
        restTemplate.getForEntity(url, JSONObject.class);
}

總結

項目中使用restTemplate的地方,在傳給restTemplate框架url的時候都進行了一次編碼,于是自己也照搬過來,殊不知restTemplate框架本身就會對url進行編碼。

其實從一個框架設計者的角度上將,urlencode是每個請求都會用到的,很順利的可以想到框架會包含這個urlencode功能,不需要編程人員將參數urlencode。

問題二:特殊字符串丟失

描述

在使用restTemplate傳遞課件標題的時候,發現有一些特殊字符串有數據丟失問題,例如傳遞課件標題:開發測試001&aaa,接收方接到的是:開發測試001,后面跟的&aaa字符丟失了。

分析

再一次懷疑是restTemplate里面自帶的編碼導致的問題,于是對比了直接使用urlencode與使用restTemplate編碼的結果,如下表:

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

明顯可以發現restTemplate對特殊字符“&”沒有進行url編碼,導致最后構建成的url是這樣的:

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

這樣就會把&aaa中的aaa當成get請求中的一個參數來看待,從而得到的title只為:%E5%BC%80%E5%8F%91%E6%B5%8B%E8%AF%95001,導致丟失了&aaa字符,接收方解析也只能得到標題為:開發測試001。

結論

restTemplate在進行url編碼的時候,不會對某些特殊字符的編碼,例如&。

方案

既然restTemplate會忽略掉某些特殊字符的url編碼,那么我們就索性不用restTemplate編碼,直接自己編碼好,跳過restTemplate的編碼,實現方案為:

?
1
2
3
4
5
6
7
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都會再一次進行編碼,而直接傳URI可以跳過restTemplate的編碼)

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/zhuxingKevin/article/details/103771933

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: a级亚洲片精品久久久久久久 | 美女被爆操 | 精品国产人妻国语 | 娇妻终于接受了3p的调教 | 99国产情在线视频 | 胸奶好大好紧好湿好爽 | 男人捅女人漫画 | 久久精麻豆亚洲AV国产品 | 国产愉拍精品视频手机 | 奇米888在线看奇米999 | 2019理论韩国理论中文 | 深夜在线影院 | 久久视频在线视频 | 色吊丝每日永久访问网站 | 亚洲精品久久久久福利网站 | 欧美大片一级片 | 特级毛片免费观看视频 | 青青草原国产在线 | 色在线看 | 日韩欧美中文在线 | 国产高清一区二区 | 青草国产在线视频 | 国产精品久久久久久岛国 | 饭冈加奈子黑人解禁在线播放 | 亚洲国产午夜看片 | 国产在线拍| 国产欧美日韩一区二区三区在线 | 51国产| 456在线观看 | 亚洲欧美日韩国产精品一区 | 黑人k8经典 | 国产成人www | 幸福草电视剧演员表介绍 | 99久久中文字幕伊人 | 精品小视频在线 | 成人先锋| 精品成人网 | 午夜AV内射一区二区三区红桃视 | daring国家队在线观看樱花动漫 | 亚洲AV久久无码精品九号 | 91porny.首页 |