一条让你再也看不懂的链接
https://user:pw@example.com:8080/path/to/page?q=hello%20world&lang=zh#section-2
10 个人里 7 个看不全这串 URL 的段。它不是密文,只是你习惯了「整条复制」,从没把它拆开看过。本文把每条 URL 的完整解剖图给你,并标清哪段进服务器、哪段只在浏览器待着。
标准解剖图
一条规范 URL 由八段组成(带 [] 的为可选):
scheme userinfo host port path query fragment
┌──────┐┌───────┐┌─────────┐┌────┐┌───────────┐┌──────────────┐┌────────┐
https:// user:pw @ example.com :8080 /path/to/page ?q=hello&lang=zh #section-2
└──┴──┘ └──────────────┘
授权部分(authority)
| 段 | 例子 | 作用 |
|---|---|---|
| scheme | https |
协议;决定端口默认值与是否加密 |
| userinfo | user:pw |
很少用;http 明文放置凭证,浏览器多已弃用 |
| host | example.com |
目标主机名或 IP |
| port | 8080 |
端口;省略取 scheme 默认 |
| path | /path/to/page |
服务器上的资源路径,可含 / 分隔层级 |
| query | q=hello&lang=zh |
键值对,& 分隔,值需百分号编码 |
| fragment | #section-2 |
浏览器端锚点,不进服务器 |
(另有少见的 query 内仍可嵌套、以及同一条可同时含 path 参数与 query,属于进阶,此处不展开。)
哪些会到服务器,哪些不会
这是最实用的一刀切分:
服务器能看到的: path + query + host + port + scheme
服务器看不到的: fragment(# 之后)——纯浏览器本地锚点
所以:
- query 会被记进服务器 access log 与统计系统;敏感内容(token、身份证号)放这里 ≡ 主动泄露给日志;
- fragment 不进服务器,也因此无法被后端用于鉴权——想用「# 藏 token」要清楚这层取舍。
path 与 query 的编码规则
URL 本质只允许 ASCII 字母数字 + . / - _ ~ 等安全字符。其余(中文、空格、%、&、?、#、+ 等)必须百分号编码:
空格 → %20
中文 → 每字节按 UTF-8,再转 %xx,如 『中』= %E4%B8%AD
& → %26 (在值里出现时必须转,否则会被当成分隔符)
别再手工拼 URL:参数值用 encodeURIComponent,整条 URL 用 encodeURI。手拼十之八九会在某个中文/特殊字符上栽跟头。
常见解析误区
- 把 fragment 当 query 用:
#之后不会发请求,页面跳转到 fragment 不产生新网络请求,只在本地滚动; - query 乱用
#/?:值里出现?、#而不转义,会把 URL 拦腰截断; +的歧义:在 query 里+常被当作空格(如application/x-www-form-urlencoded),而在 path 里它是字面加号——同一字符两套语义;- 默认端口依赖 scheme:省略端口不等于没有端口,解析器会按 80/443 补全。
用解析器把段拆开验证
别用肉眼在长链接里找分隔符——把链接丢进 URL 解析 工具,让它把 scheme/host/port/path/query/fragment 逐段列出来,再对一份正常/异常的对照,最能暴露你自己写错的那段。配合 URL 编码/解码工具把中文与特殊字符的 %xx 展开,解析的边界感一次性建立。
自查
下面对这个 URL,不借助工具写出它的八段划分:
https://a.com:8443/api/v1/items?tag=dev%20tools&lang=en#top
- 哪段会进服务器日志?
%20对应哪个字符?- 若要在 query 值里表示
&,怎么写?
把三点想清楚,URL 在你手里就不再是「一串认不出的字符」。