url请求中带有+等不符合ASCII编码的字符解决⽅法及原理问题分析:
查了下JS encode 的相关内容, 总于发现+ 号的秘密。
html中因为⼀些⾮标准的做法,将+ 等同于空格进⾏处理(当Html 的表单被提交时,每个表单域都会被Url 编码之后才在被发送。由于历史的原因,表单使⽤的Url 编码实现并不符合最新的标准。例如对于空格使⽤的编码并不是%20 ,⽽是+ 号,如果表单使⽤的是Post ⽅法提交的,我们可以在HTTP 头中看到有⼀个Content-Type 的header ,值为 application/x-www-form-urlencoded ,⼤部分应⽤程序均能处理这种⾮标准实现的Url 编码)。
在搜索引擎中做了下尝试:
keyword = e h 变送器 , url = ( 空格被转化为+ 号)
keyword = e+ h 变送器 , url = (+ 号被进⾏了转义为%2B ,程序才能正常处理)
思路2 :
继续追查对应的_input_charset=utf-8 未⽣效的原因,DEBUG 看到在SetLocaleValve 中的确设置了request.setCharsetEncoding 为utf-
8 。初步怀疑是否跟jboss server 的配置有关,查了下跟URIEncoding 和useBodyEncodingForURI 设置有关。⽬前公司所使⽤的jboss 为4.05 ,对应俄tomact 配置中只指定了对应的URIEncoding=GBK 。正因为这样,导致设置的_input_charset 针对GBK 的提交没有效果,还是按照GBK 进⾏解析。
1. 考虑将请求由GET 换成POST ,这样就可以使⽤_input_charset
但在实施过程中,和UED 沟通过程,针对POST 的会引起⼀个跨域请求的问题。此⽅案⼜只能做罢
思路3 (实践成功) :
1. UED 进⾏伪url encode 的实现 , 将+ 号进⾏%2B 的编码。因为⽬前JS 中没有现成的函数,这⾥只是通过replace(/\+/g, '%2B') 进⾏了转化。
总结
针对+ 号的处理,针对不同的业务场景需要不同的处理⽅案,描述下⼏种场景:
1. ⾮Ajax 请求
可以直接使⽤Form 表单的 GET ,POST 的urlencode 协议,⾃动实现+ => %2B 的转化
2. Ajax 请求
* GET 请求 : 很⽆奈,只能使⽤⽅案3 ,⼈为进⾏+ 号转化。
* POST 请求( 同⼀应⽤,⾮跨域请求) : 使⽤encodeURIComponent + _input_charset=utf-8 指定编码进⾏处理。
ps: 前⾯提的这⼏种⽅案,都是基于+ 号是正常的业务场景进⾏考虑。同时我们也可以从业务层⾯进⾏⼀个梳理,+ 号处理是否有其必要性,能从业务数据⼊⼝直接规避那就最好了。
在线url网址编码解码背景知识:
URIEncoding 和useBodyEncodingForURI
对于URL 提交的数据和表单中GET ⽅式提交的数据,在接收数据的JSP 中设置request.setCharacterEncoding参数是不⾏的,因为在Tomcat5.0 中,默认情况下使⽤ISO- 8859-1 对URL 提交的数据和表单中GET ⽅式提交的数据进⾏重新编码(解码),⽽不使⽤该参数对URL 提交的数据和表单中GET ⽅式提交的数据进⾏重新编码(解码)。要解决该问题,应该在Tomcat 的配置⽂件的Connector 标签中设置useBodyEncodingForURI 或者URIEncoding 属性,其中useBodyEncodingForURI 参数表⽰是否⽤ request.setCharacterEncoding 参数对URL提交的数据和表
单中GET ⽅式提交的数据进⾏重新编码,在默认情况下,该参数为false (Tomcat4.0 中该参数默认为
true );URIEncoding参数指定对所有GET ⽅式请求(包括URL 提交的数据和表单中GET ⽅式提交的数据)进⾏统⼀的重新编码(解码)的编码。 URIEncoding 和useBodyEncodingForURI 区别是,URIEncoding 是对所有GET ⽅式的请求的数据进⾏统⼀的重新编码(解码),⽽useBodyEncodingForURI 则是根据响应该请求的页⾯的request.setCharacterEncoding 参数对数据进⾏的重新编码(解码),不同的页⾯可以有不同的重新编码(解码)的编码。所以对于URL 提交的数据和表单中GET ⽅式提交的数据,可以修改 URIEncoding 参数为浏览器编码或者修改useBodyEncodingForURI 为true ,并且在获得数据的JSP 页⾯中 request.setCharacterEncoding参数设置成浏览器编码。
为什么需要Url 编码
1. Url 中有些字符会引起歧义 , =,& 号等
2. Url 的编码格式采⽤的是ASCII 码,⽽不是Unicode ,这也就是说你不能在Url 中包含任何⾮ASCII 字符,例如中⽂
哪些字符需要编码
RFC3986 ⽂档规定,Url 中只允许包含英⽂字母(a-zA-Z )、数字(0-9 )、-_.~4 个特殊字符以及所有保留字符。
Url 可以划分成若⼲个组件,协议、主机、路径等。RFC3986 中指定了以下字符为保留字符: ! * ' ( ) ; : @ & =+ $ , / ? # [ ]
如何对Url 中的⾮法字符进⾏编码
Url 编码通常也被称为百分号编码(Url Encoding ,also known as percent-encoding ),是因为它的编码⽅式⾮常简单,使⽤% 百分号加上两位的字符——0123456789ABCDEF—— 代表⼀个字节的⼗六进制形式。Url 编码默认使⽤的字符集是US-ASCII 。例如a 在US-ASCII 码中对应的字节是0x61 ,那么Url 编码之后得到的就是% 61 ,我们在地址栏上输⼊ASCII 字符集中对应的字节为0x40 ,经过Url 编码之后得到的是%40 。
Javascript 中的escape,encodeURI 和encodeURIComponent 的区别
Javascript 中提供了3 对函数⽤来对Url 编码以得到合法的Url ,它们分别是escape / unescape,encodeURI / decodeURI 和encodeURIComponent / decodeURIComponent 。解码和编码的过程是可逆的.
兼容性不同
escape 函数是从Javascript1.0 的时候就存在了,其他两个函数是在Javascript1.5 才引⼊的。但是由于Javascript1.5 已经⾮常普及了,所以实际上使⽤encodeURI 和encodeURIComponent 并不会有什么兼容性问题。
对Unicode 字符的编码⽅式不同
这三个函数对于ASCII 字符的编码⽅式相同,均是使⽤百分号+ 两位⼗六进制字符来表⽰。但是对于Unicode 字符,escape 的编码⽅式是% uxxxx ,其中的xxxx 是⽤来表⽰unicode 字符的4 位⼗六进制字符。这种⽅式已经被W3C 废弃了。但是在ECMA-262 标准中仍然保留
着 escape 的这种编码语法。encodeURI 和encodeURIComponent 则使⽤UTF-8 对⾮ASCII 字符进⾏编码,然后再进⾏百分号编码。这是RFC 推荐的。因此建议尽可能的使⽤这两个函数替代escape 进⾏编码。
适⽤场合不同
encodeURI 被⽤作对⼀个完整的URI 进⾏编码,⽽encodeURIComponent 被⽤作对URI 的⼀个组件进⾏编码。
安全字符不同
escape (69 个) */@+-._0-9a-zA-Z
encodeURI (82 个) !#$&'()*+,/:;=?@-._~0-9a-zA-Z
encodeURIComponent (71 个) !'()*-._~0-9a-zA-Z (注意+ 号未在其安全字符⾥)
其他和Url 编码相关的问题
对于包含中⽂的Url 的处理问题,不同浏览器有不同的表现。例如对于IE ,如果你勾选了⾼级设置“ 总是以UTF-8发送Url” ,那么Url 中的路径部分的中⽂会使⽤UTF-8 进⾏Url 编码之后发送给服务端,⽽查询参数中的中⽂部分使⽤系统默认字符集进⾏Url 编码。为了保证最⼤互操作性,建议所有放到 Url 中的组件全部显式指定某个字符集进⾏Url 编码,⽽不依赖于浏览器的默认实现。
另外,很多HTTP 监视⼯具或者浏览器地址栏等在显⽰Url 的时候会⾃动将Url 进⾏⼀次解码(使⽤UTF-8 字符集),这就是为什么当你
在 Firefox 中访问Google 搜索中⽂的时候,地址栏显⽰的Url 包含中⽂的缘故。但实际上发送给服务端的原始Url 还是经过编码的。你可以在地址栏上使⽤Javascript 访问location.href 就可以看出来了。在研究Url 编解码的时候千万别被这些假象给迷惑了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论