背景描述: 项目经常需要在前端使用富文本编辑器,将编辑内容传递到后台;项目新加了防XSS攻击相关,会过滤一些特殊符号(<>;’"等),恰恰这些符号在富文本编辑器中常出现(html格式),所以想到了多富文本编辑器拿到的内容进行url编码,再到后台使用java解码,这样就可以保留住特殊符号;
好啦,思路已明确,开干
- js对文本url编码
console.log(encodeURI('<p><span style="font-weight: bold;">测试</span></p>'))
编码后:%3Cp%3E%3Cspan%20style=%22font-weight:%20bold;%22%3E%E6%B5%8B%E8%AF%95%3C/span%3E%3C/p%3E
- java url解码
System.out.println(URLDecoder.decode("%3Cp%3E%3Cspan%20style=%22font-weight:%20bold;%22%3E%E6%B5%8B%E8%AF%95%3C/span%3E%3C/p%3E", "utf-8"));
解码后: <p><span style="font-weight: bold;">测试</span></p>
好啦,至此从JS到后端保存到数据库一切正常;
接下来,从后端读取后再返回给前端,由于后端返回前也做了XSS过滤,所以需要先JAVA编码再JS解码。
- Java url编码
System.out.println(URLEncoder.encode("<p><span style=\"font-weight: bold;\">测试</span></p>","utf-8"));
java编码:%3Cp%3E%3Cspan+style%3D%22font-weight%3A+bold%3B%22%3E%E6%B5%8B%E8%AF%95%3C%2Fspan%3E%3C%2Fp%3E
- js 解码
decodeURI('%3Cp%3E%3Cspan+style%3D%22font-weight%3A+bold%3B%22%3E%E6%B5%8B%E8%AF%95%3C%2Fspan%3E%3C%2Fp%3E')
解码后:<p><span+style%3D"font-weight%3A+bold%3B">测试<%2Fspan><%2Fp>
解码后发现已无法在富文本编辑器显示,格式已丢失,原因是JS对JAVA编码后的内容解码失败!
查找问题过程略,直接说结论:
JS URL编码有两个方法, encodeURI和encodeURIComponent;encodeURIComponent名字长干的事也多
encodeURI() 函数可把字符串作为 URI 进行编码。对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的: , / ? : @ & = + $ #
encodeURIComponent() 函数可把字符串作为 URI 组件进行编码。
该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ’ ( ) 。
其他字符(比如 :;/?: @&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。
简而言之:
encodeURI和decodeURI不会对 ;/?: @&=+$,# 进行转义
encodeURIComponent和decodeURIComponent会对 ;/?: @&=+$,# 进行转义;
而JAVA考虑到跨平台,也会对 ;/?: @&=+$,# 进行转义,所以当使用java对全部字符编码,使用encodeURI无法对编码后的特殊字符解码,导致了问题的发生;
这时想到JS使用decodeURIComponent解码就好了啊,咱们试下
decodeURIComponent('%3Cp%3E%3Cspan+style%3D%22font-weight%3A+bold%3B%22%3E%E6%B5%8B%E8%AF%95%3C%2Fspan%3E%3C%2Fp%3E')
解码后: <p><span+style="font-weight:+bold;">测试</span></p>
也无法正常解码,原因是 JAVA对 空格 编码后是 +, 而js对空格编码是%20,所以需要将java编码后内容中+替换为%20再使用JS解码
decodeURIComponent('%3Cp%3E%3Cspan+style%3D%22font-weight%3A+bold%3B%22%3E%E6%B5%8B%E8%AF%95%3C%2Fspan%3E%3C%2Fp%3E'.replace(new RegExp('\\+', 'g'), '%20'))
解码后:<p><span style="font-weight: bold;">测试</span></p>
结论:
js -> java
页面可以使用 encodeURI或者 encodeURIComponent 进行编码
后端使用URLDecoder 解码
java -> js
后端使用URLEncoder编码
页面使用 decodeURIComponent(encodeStr.replace(new RegExp(’\+’, ‘g’), ‘%20’)) 进行解码。
最后留个疑问: 为什么 js->Java 可以使用 encodeURI 而且没有对空格进行转换,而 Java->js 需要注意这两地方呢.
倒过来看看原因吧😺