中年|大侠稍等!URL 中为何出现奇怪的字符( 二 )


虽然, 这不会影响图片的打开 , 地址依旧是有效的 。 但是为什么浏览器要把中文转换成这种奇怪的形式呢?
我们先来看一个例子 。 如果访问下面这个 URL 链接:
https://www.baidu.com/s?wd=?#!
这是使用百度进行搜索的一个链接 ,/s 后面跟着的 ? 代表请求参数(query) , 也就是我们想向请求的服务器提交一些参数 。 wd 为百度规定的查询参数名 , wd 后边跟着的就是需要搜索的内容 。

我们想搜索 ?#! 这个内容 , 可是当你复制这个链接放在浏览器中打开时 , 会发现一个问题 , 百度仅仅是搜索了 ? 这个内容 , #! 不见了 。
中年|大侠稍等!URL 中为何出现奇怪的字符
本文插图

为什么呢?如果你仔细看上面那张 URL 的构成图 , 会发现 URL 结构中还有一个锚点(fragment)的部分 , 分隔符号就是 # 。
所以这里就会出现一个问题 , 我们的业务需求是将 # 当做一个普通文本来进行搜索 , 但是 # 在 URL 中有特定的意思 , 所以浏览器就遇到了一个解释歧义的问题 。
中年|大侠稍等!URL 中为何出现奇怪的字符
本文插图

这就引申出一个问题 , URL 在数据传递中 , 如果存在用作分隔符等特殊作用的保留字符怎么办?
在实际的业务场景中 , 会经常碰到一些在 URL 中有歧义性的数据 , 为了避免解释错误 , 开发者想出了一个解决方法 , 就是对这些数据进行一定的处理 , 从而解决歧义的问题 。 处理的方法有很多种 , 最常用的处理方式 , 就是对歧义性的数据进行 URL 百分号编码 。
哪些是会引起歧义的数据呢?
根据 RFC 3986(https://tools.ietf.org/html/rfc3986#appendix-A)的规定 , 我们可以得到下面的结果 。
不在 ASCII 码范围内的字符 (URL 使用 ASCII 码进行编解码)
ASCII 码中不可显示的字符

URL 中规定的保留字符
不安全字符(传输环节中可能会被不正确处理) , 如空格、引号、尖括号等
保留字符由组件分隔符(gen-delims)和子组件分隔符(sub-delims)组成 , 这些字符在 URL 中都有特殊的意义:
Reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims = "!" / "$" / "&amp" / """ / "(" / ")" / "*" / "+" / "," / "" / "="
URL 中可以直接使用的非保留字符则有:
Unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA:%41 - %5A AND %61 - %7A (英文字母大写 A-Z 以及英文字小写 a-z)
DIGIT:%30 - %39 (数字 0-9)
-: %2D .: %2E _: %5F
~: %7E (某些服务实现将其作为保留字符 , 一般也需要进行编码处理)
这下子我们就了解了 , 为什么 URL 中有时会出现奇怪的字符 , 很多时候浏览器会自动帮我们做编码和解码的操作 。 就像“向日葵”的 URL 一样 , 中文部分因为并不在 ASCII 码中 , 于是浏览器进行 URL 百分号编码的形式来进行访问 。
【中年|大侠稍等!URL 中为何出现奇怪的字符】(又拍云服务名的合法范围就是在非保留字符中获取 , 而不能指定为任意字符)
编码的形式
最常见的编码形式就是百分号编码(pct-encoded) , 这也是浏览器默认的编码形式 。pct-encoded = "%" HEXDIG HEXDIG

百分号编码一个保留字符, 首先需要把该字符的 ASCII 的值表示为两个 16 进制的值, 然后在其前面放置转义字符(%) 。 对于非 ASCII 字符, 则需要转换为 UTF-8 字节序, 然后每个字节按照上述方式表示 。
(感兴趣的同学可以参考百分号编码 https://zh.wikipedia.org/zh-hans/%E7%99%BE%E5%88%86%E5%8F%B7%E7%BC%96%E7%A0%81 条目)


推荐阅读