緣由:
在一個項目中,app請求tcpdump日志與記錄的日志內容不一致
請求%2B
識別成 +
請求 +
識別成 空格
這個在base64解密的時候會出現異常,base64需要的是加號,而不是空格
造成的原因:
在js中,對url的加密分別由三種方式:
escape("aa+aa aa")
"aa+aa%20aa"
encodeURI("aa+aa aa")
"aa+aa%20aa"
encodeURIComponent("aa+aa aa")
"aa%2Baa%20aa"
第三種方式,+
變成%2B
java代碼:
System.out.println(URLEncoder.encode("aa+aa aa","UTF-8"));
aa%2Baa+aa
特么加號變成%2B,空格變成加號
如果是沒經過加密,但是解密了
System.out.println(URLDecoder.decode("aa+aa aa","UTF-8"));
aa aa aa
好吧,從這里就可以看出,為什么base64解密報錯了
app端進行base64加密,內部含有+
,然后並沒有進行url加密,直接傳給后端,后端對其先進行Url解密,+
變成了空格,再進行base64解密,所以報錯。
規范:
造成這種混亂局面的原因在於:
W3C標准規定,當Content-Type為application/x-www-form-urlencoded時,URL中查詢參數名和參數值中空格要用加號+替代,所以幾乎所有使用該規范的瀏覽器在表單提交后,URL查詢參數中空格都會被編成加號+。
而在另一份規范(RFC 2396,定義URI)里, URI里的保留字符都需轉義成%HH格式(Section 3.4 Query Component),因此空格會被編碼成%20,加號+本身也作為保留字而被編成%2B,對於某些遵循RFC 2396標准的應用來說,它可能不接受查詢字符串中出現加號+,認為它是非法字符。所以一個安全的舉措是URL中統一使用%20來編碼空格字符。
Java中的URLEncoder本意是用來把字符串編碼成application/x-www-form-urlencoded MIME格式字符串,也就是說僅僅適用於URL中的查詢字符串部分,但是URLEncoder經常被用來對URL的其他部分編碼,它的encode方法會把空格編成加號+,與之對應的是,URLDecoder的decode方法會把加號+和%20都解碼為空格,這種違反直覺的做法造成了當初我對空格URL編碼問題的困擾。
因此后來我的做法都是,在調用URLEncoder.encode對URL進行編碼后(所有加號+已被編碼成%2B),再調用replaceAll(“+”, “%20″),將所有加號+替換為%20。