为什么 decodeURIComponent 解码的地址和实际地址不一致?
1. 起因
最近在开发一个项目, 需要获取当前页面的地址, 然后进行解码, 发现 decodeURIComponent 解码的地址和实际地址不一致, 然后 debug 了下, 发现是前端执行了如下操作:
let url = encodeURIComponent(location.href);
2. 原因
因为 location.href 返回的地址中包含了中文, 浏览器会自动对中文进行编码, 然后将编码后的地址赋值给 url, 最后执行 decodeURIComponent 解码
这其实进行了了两次编码, 可以改成:
let url =encodeURIComponent(decodeURIComponent(location.href))
当然, encodeURI 的表现效果也一样, 只是 encodeURI 编译的范围小一些而已
3. 扩展
3.1. 那么为什么 浏览器中 location.href 返回的地址会自行编译中文呢
浏览器中的 location.href
属性返回的是当前页面的完整 URL 地址,包括协议、主机名、端口号、路径以及查询参数等。当页面中存在中文字符时,这些中文字符会被浏览器自动编码成 URL 可接受的格式。
这种自动编码过程属于 URL 编码(URL encoding),其目的是确保 URL 中不含有特殊字符或非法字符,从而保证 URL 在网络上传输和解析时的正确性和可靠性。
例如,如果当前页面的 URL 包含中文字符 "你好",则 location.href
返回的地址中会将这些中文字符编码为相应的 UTF-8 编码格式,比如 %E4%BD%A0%E5%A5%BD
。这样做是为了避免可能产生的 URL 歧义或错误解析。
因此,无论是在 JavaScript 中访问 location.href
,还是直接在地址栏中查看页面的 URL,浏览器都会对其中的中文字符进行 URL 编码处理,以确保 URL 的正确性和可靠性。
3.2. 编码例子
以下是多次编码的例子:
decodeURIComponent('sasd//') 'sasd//' encodeURIComponent('as//') 'as%2F%2F' encodeURIComponent(encodeURIComponent('as//')) 'as%252F%252F' encodeURIComponent(encodeURIComponent(encodeURIComponent('as//'))) 'as%25252F%25252F' 这个是什么原因
在您提供的例子中,逐步对字符串 "as//" 进行多次 encodeURIComponent
编码后会产生这种现象。让我们一步步解释:
对 "as//" 执行一次
encodeURIComponent
:javascriptencodeURIComponent("as//"); // 'as%2F%2F'
正常编码后得到
'as%2F%2F'
,其中/
被编码为%2F
。对第一次编码结果
'as%2F%2F'
再次执行encodeURIComponent
:javascriptencodeURIComponent("as%2F%2F"); // 'as%252F%252F'
这里需要注意的是,对
%
字符进行编码,其 ASCII 值为 0x25,被编码后为%25
,而%
在 URL 编码中代表特殊含义,因此会被再次编码为%2525
。对第二次编码结果
'as%252F%252F'
再次执行encodeURIComponent
:javascriptencodeURIComponent("as%252F%252F"); // 'as%25252F%25252F'
同样地,这里的
%
也会被再次编码,依次类推。
4. 总结
简言之,每次对已经编码过的字符串再次执行 encodeURIComponent
时,会将原字符串中的 %
符号解释为特殊含义(URL 编码),从而导致多次编码产生级联效应,最终使得结果不断叠加变化。
如果您想要保持稳定的编码结果,建议在每次解码前先进行一次编码,确保每次解码的字符串都是统一编码状态。