【原创】浏览器请求和JAVA中空格和加号+编码原理解析
一、编码对比
1、浏览器中
(1)encodeURI 编码
(2)encodeURIComponent编码
2、JAVA中
(1)编码
1 | String blankEn = URLEncoder.encode(" ", "UTF-8"); |
(2)解码
1 | String plusDe = URLDecoder.decode("+", "UTF-8"); |
3、对比
(1)编码
| 编码前字符 | encodeURI后 | encodeURIComponent后 | JAVA中encode |
|---|---|---|---|
| 空格 | %20 | %20 | + |
| + | + | %2B | %2B |
(2)解码
| 解码前字符 | decodeURI后 | decodeURIComponent后 | JAVA中decode |
|---|---|---|---|
| + | + | + | 空格 |
| %20 | 空格 | 空格 | 空格 |
| %2B | + | + | + |
(1)java中为何会将空格编码成为+呢?
(2)java中+和%20都会解码成为空格,那么如果知道浏览器传过来的请求参数到底是加号还是空格,如何避免该问题?
(3)get方式请求时,java后台从HttpServletRequest中获取参数 request.getParameter(‘’)会自动对编码后的参数进行解码。
二、常见问题
1、前端使用 encodeURI对参数进行编码,编码后使用get方式进行请求,此时+编码后结果仍为+,Java后台使用request.getParameter(‘’)获取参数时,自动将+后解码为空格,造成参数错误。例如前端参数使用Base64对参数进行编码时,编码值中经常会含有+,易造成错误。
2、浏览器前端编码后将空格编码成为+,此时使用post方式请求后台获取参数,如果不主动进行解码,此时获取的+无法还原为空格。浏览器前端不是实测不论encodeURI还是encodeURIComponent都将空格编码为%20么,又如何会像java一样编码成+
三、原理剖析
1、URL传递过程中加号(+)变成空格的原因
主要源自于URL编码规则的历史约定以及浏览器对URL参数解析的方式。具体解释如下:
(1)URL编码原则:URL(Uniform Resource Locator)的设计要求其内容必须是可打印的ASCII字符集,并且某些特定字符具有特殊的含义,如/用于分隔路径组件,?用于标记查询字符串的开始,&用于分隔多个查询参数等。对于其他非字母、数字及保留字符(如空格、加号等),需要进行编码以确保它们能在URL中安全传输。
(2)空格的编码:空格在URL中不是一个合法的未编码字符。按照RFC 3986标准,空格应被编码为%20。然而,在早期的网络应用和一些非正式规范(如Netscape的MIME类型应用程序WWW表单)中,出于简化和兼容性考虑,空格常常被约定俗成地用加号(+)来表示。这种用法尤其常见于HTTP GET请求的查询字符串中。
(3)浏览器行为与解码逻辑:当浏览器接收到一个包含查询参数的URL时,它会对查询字符串进行解码以便提取参数及其对应的值。在执行解码操作时,浏览器遵循RFC 3986标准,并根据该标准,将加号(+)视为等同于空格进行解码。因此,即使在构造URL时原本意图传递的是加号字符,浏览器在解析时仍会将其解释为表示空格的符号。
综上所述,URL传递过程中加号变成空格是因为浏览器遵循了将加号作为空格替代符的传统约定,在解析URL查询字符串时进行了相应的解码处理。为了避免这种情况,当需要在URL中传递真正的加号时,应当使用其正确的URL编码形式%2B,以确保加号能够准确无误地到达服务器端。
2、 encodeURIComponent
是一个JavaScript 内置的全局函数,用于对URI(统一资源标识符)组成部分进行编码,确保其包含的所有字符都能在各种环境下正确传递和解析。这个函数主要应用于URL查询字符串、路径段或其他需要嵌入到URL中的字符串的编码。以下是对encodeURIComponent函数的详细说明:
(1)功能
encodeURIComponent(str)接收一个字符串参数str,并返回一个新的字符串,其中所有非字母、数字字符(除了-、.、_和~这四个保留字符)以及任何非ASCII字符,都被替换为对应的百分号(%)编码序列。
(2)编码规则
对于ASCll空格字符(Unicode值为U+0020),它被编码为%20。
对于ASCII非字母数字字符(除了保留字符-、.、_和~),它们各自被转化为对应的%xy形式的十六进制编码,其中xy是字符的 Unicode编码值。
对于非ASCII字符(即Unicode编码大于U+007F 的字符),它们会被转化为UTF-8字节序列,然后每个字节分别被编码为%xy%yz%zx形式的十六进制编码。
(3)适用场景
查询字符串参数:当需要将用户输入或动态数据作为 URL查询参数时,必须使用encodeURIComponent 对这些值进行编码,以防止特殊字符导致解析错误或潜在的安全问题(如跨站脚本攻击(XSS))。
路径段:如果URL路径中包含动态生成的部分(如文件名或路径参数),也需要使用encodeURIComponent进行编码,确保路径中的特殊字符不会引起解析错误。
片段标识符(fragment identifier):URL 中的片段标识符(即#后面的部分)如果包含特殊字符,也应使用encodeURIComponent 进行编码。
(4)与相似函数的区别
encodeURI:此函数用于对整个URI进行编码,而不仅仅是URI的某个部分。它不会对URI中的保留字符(如/、:、;、?、&、=等)进行编码,因为这些字符在URI中具有特定含义。因此,对于查询字符串参数或路径段,应使用encodeURIComponent而不是encodeURI。
escape:这是一个较I旧的函数,不推荐在现代JavaScript 代码中使用。它的编码范围有限,不符合现代URI 编码标准。始终优先使用encodeURIComponent。
四、总结
如果请求参数中有空格、+或者其它特殊字符的话,前端传参使用encodeURIComponent进行编码,请求事使用post方式,避免getParameter时自动解码。


