← 返回博客首页

URL 的每一段到底是什么:scheme/host/path/query/fragment

一条让你再也看不懂的链接

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 在你手里就不再是「一串认不出的字符」。

常见问题

URL 里哪一段会发送给服务器,哪一段不会?

**fragment(# 之后的锚点)不会发送给服务器**,它纯粹是浏览器本地定位(滚动到页面某个 id)。路径 path 中的**查询段对服务器可见**(受服务端日志与站点统计)。而 query 里用户填的敏感值会进服务器日志。要理解边界:服务器只看到从 scheme 后到 query 的部分(不含 #fragment),fragment 只存在于浏览器地址栏。这也是为何『把 token 塞进 # 防泄漏』是常见但不可靠的做法——它不进服务器,但也因此无法被后端鉴权。

为什么 URL 里有中文/空格会打不开,但有的又能?

标准 URL 只允许 ASCII 的字母数字和少数符号,中文、空格等**必须做百分号编码**。浏览器一般会自动把地址栏里的中文/空格转成 %xx(UTF-8 字节再编码),所以『打不开』大多发生在:①后端拼 URL 时没编码直接把中文拼进去;②日志/链接里保留了未编码的空格被截断;③浏览器对某些场景不会自动转(如 cookie、location 手工赋值)。规范做法:拼 URL 用 `encodeURIComponent` 对**参数值**编码、`encodeURI` 对整个 URL 编码,别用手工字符串拼接。可用 URL 编码工具验证 %xx 对照。

URL vs URI vs URN 到底什么关系?

一句话:**URI ⊇ URL, URN**。URI(统一资源标识符)是最宽的概念——只要能『标识』一个资源就算,不论能否访问。URL(定位器)是 URI 的一种:不光标识,还给出**访问方式与位置**(scheme + host + path),如 `https://a.com/x`。URN(名字)也是 URI 的一种:用稳定的、位置无关的名字标识资源,如 `urn:isbn:...`。现实中『URL』与『URI』经常混用,多数工具站与文档称 URL,但你遇到接收 URI 的接口时,传 URL 一定合法;反之不保证。

为什么同样的 address,跨浏览器/跨站点解析出的端口、路径会不一样?

因为很多部分是**可选且有默认值**的:①端口省略时按 scheme 取默认(http→80,https→443);②'http://'、'www.' 等前缀可能被补全;③相对路径会按当前页解析成绝对路径;④query 是否保留空参数、fragment 是否参与排序键,各实现不一致。所以『看起来相同』的 href,经不同解析器拆出的端口/path 可能不同。要准确就别靠肉眼,把同一 URL 丢进 URL 解析/格式化工具对比各字段,很多看似玄学的差异其实只是默认值规则。

← 返回博客首页