缘由:
在一个项目中,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。
参考: