Skip to content
📈0️⃣

为什么 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 编码后会产生这种现象。让我们一步步解释:

  1. 对 "as//" 执行一次 encodeURIComponent

    javascript
    encodeURIComponent("as//"); // 'as%2F%2F'

    正常编码后得到 'as%2F%2F',其中 / 被编码为 %2F

  2. 对第一次编码结果 'as%2F%2F' 再次执行 encodeURIComponent

    javascript
    encodeURIComponent("as%2F%2F"); // 'as%252F%252F'

    这里需要注意的是,对 % 字符进行编码,其 ASCII 值为 0x25,被编码后为 %25,而 % 在 URL 编码中代表特殊含义,因此会被再次编码为 %2525

  3. 对第二次编码结果 'as%252F%252F' 再次执行 encodeURIComponent

    javascript
    encodeURIComponent("as%252F%252F"); // 'as%25252F%25252F'

    同样地,这里的 % 也会被再次编码,依次类推。

4. 总结

简言之,每次对已经编码过的字符串再次执行 encodeURIComponent 时,会将原字符串中的 % 符号解释为特殊含义(URL 编码),从而导致多次编码产生级联效应,最终使得结果不断叠加变化。

如果您想要保持稳定的编码结果,建议在每次解码前先进行一次编码,确保每次解码的字符串都是统一编码状态。