原創:扣釘日記(微信公眾號ID:codelogs),歡迎分享,非公眾號轉載保留此宣告,
問題發生
上上周,看到一位老哥找我們組同事聯調介面,不知道是什么問題,兩人坐一起搞了快1個小時,看起來好像有點復雜,
突然,老哥發出一聲臥槽,"我傳參里的+號,到你這怎么變成了空格!",這個聲音很大,我明顯的聽到了,很快,我就大概Get到了他們的問題點,
我猜測他們遇到的問題大概如下:
- 我們的介面協議上,都會將請求資料做一次base64編碼,然后放到data引數上,
- 然后某些資料做base64編碼后有
+,如{"notes":"代碼"}base64編碼為eyJub3RlcyI6IuS7o+eggSJ9Cg==, - 然后直接拼到data引數上,即
data=https://www.cnblogs.com/codelogs/archive/2023/03/25/eyJub3RlcyI6IuS7o+eggSJ9Cg==,組織成http請求發出,
如果寫成等價的curl,就是這樣:
$ curl http://localhost:8080/send -d 'data=https://www.cnblogs.com/codelogs/archive/2023/03/25/eyJub3RlcyI6IuS7o+eggSJ9Cg=='
寫個測驗介面除錯下看看,如下:

這就是他們遇到的問題,+會變成空格,這個坑其實蠻容易踩到,我自己剛作業時就踩到過這個坑,也多次看到或聽到別人同踩此坑??
問題原因
這個問題和urlencode編碼有關,urlencode編碼,一般來說,除字母、數字和*,.,-和_這些位元組原樣輸出外,其它位元組都會編碼為%XX(16進制)的形式,

但有一個特例,如下:
String enc = URLEncoder.encode(" ", "UTF-8");
System.out.println(enc); // 輸出+號
String dec = URLDecoder.decode("+", "UTF-8");
System.out.println(dec); // 輸出空格
特例就是空格會被編碼為+號,反之,+號會被解碼為空格!
注:在新的RFC 2396規范中,空格其實也可以編碼成%20,而解碼時,
+號與%20都會被解碼為空格,
回想上面的場景,如果將帶有+號的base64字串,原封不動的封裝到data=https://www.cnblogs.com/codelogs/archive/2023/03/25/中,再發送給Tomcat等Web服務器,若Tomcat側做一次urldecode解碼,+是不是就變成空格了??
而Tomcat確實會做urldecode解碼這樣的操作,當呼叫方的Content-Type為application/x-www-form-urlencoded時,這里知道有這種操作即可,想了解細節可看看我寫的這篇文章 由x-www-form-urlencoded引發的介面對接失敗
解決問題
解決這種問題,主要有兩種方法,如下:
- 呼叫方對引數做urlencode編碼,
按規范來看,當Content-Type為application/x-www-form-urlencoded時,呼叫方是必須對引數名與引數值做urlencode的,java實作如下:
String base64Str = Base64.getEncoder().encodeToString(data);
String requestStr = "data="https://www.cnblogs.com/codelogs/archive/2023/03/25/+ URLEncoder.encode(base64Str,"UTF-8");
這里做了urlencode后,+會被編碼為%2B,再由服務端解碼,就會變成原樣的+號,
注:如果是使用apache的HttpClient,可考慮使用
UrlEncodedFormEntity,它會自動做這個事情,
- 使用urlsafe版本的base64,
普通的base64不能直接作為引數值,因為它可能包含+、/這兩個url不安全的字符,所以base64有個變種叫urlBase64,它將+、/替換成了url安全的-、_,java實作如下:
String urlBase64Str = Base64.getUrlEncoder().encodeToString(data);
String requestStr = "data="https://www.cnblogs.com/codelogs/archive/2023/03/25/+ urlBase64Str;
關于base64、urlencode編碼,之前也專門寫過一篇文章,感興趣可進一步閱讀 hex,base64,urlencode編碼方案對比
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/548147.html
標籤:其他
