URI 是总称,URL 是其中「说位置」的一类,URN 是「说名字」的一类。日常说的网址几乎全是 URL。
上一节收口了链路。这一节回到起点:请求行里那个 /index.html 到底是什么。
一、三个词的关系
URI(Uniform Resource Identifier)是让一个资源可以被唯一指认的字符串。它有两个子集:
- URL:给位置。https://example.com/a.html 说的是「去哪拿」。
- URN:给名字。urn:isbn:9787115351531 说的是「它是什么」,不说在哪。
这张关系图在任何一本讲网络的教材里都出现过,但绝大多数人只记住「URL 就是网址」。
实际写代码时,URN 的存在感几乎为零,因为「按名字找」需要一个全局解析体系,现实里只有 ISBN、
UUID 这类东西在局部用。
二、URL 的五个部件
用 urllib.parse.urlsplit 拆一个完整 URL,会得到五个字段:scheme(协议)、
netloc(主机与端口)、path(路径)、query(查询串)、fragment(片段)。
其中 fragment 只在浏览器本地生效,根本不会发给服务器。
这一条最常被误解:#top 锚点在 HTTP 请求里是不存在的,
所以服务端拿不到它(SPA 用 # 做路由是另一回事)。
netloc 里还可能有 user:password@,这是 HTTP 基本认证的老写法。
现在浏览器基本不认了,因为把密码写在地址里极其危险。
三、相对引用为什么能省那么多字
Demo 里 /a/b.html 这种只给路径的写法叫相对引用。它要结合当前页面的地址才能算出完整地址。
相对引用是 HTML 体积能压下来的重要原因之一:同一个站点里几百个链接,
全都省掉 https://example.com 这二十多个字符。
但它也带来歧义:b.html 和 /b.html 和 ./b.html 在不同当前路径下指向不同地方。
写链接时用绝对路径(以 / 开头)几乎总是更安全的选择。
四、动手 Demo:拆五种 URI,看它们各属于哪一类
拿五条形态各异的串,逐个拆成五个字段,再判断它属于 URL、URN 还是相对引用。
for s in samples:
p = urllib.parse.urlsplit(s)
print(u'scheme', p.scheme, u'netloc', p.netloc,
u'path', p.path, u'query', p.query,
u'fragment', p.fragment)
实跑输出:
--------------------------------------------------------------------
URI、URL、URN:三个名字一件事
--------------------------------------------------------------------
原串 https://user:[email protected]:8443/a/b.html?x=1&y=2#top
scheme https
netloc user:[email protected]:8443
path /a/b.html
query x=1&y=2
fragment top
归类 URL:给位置
原串 mailto:[email protected]
scheme mailto
netloc (空)
path [email protected]
query (空)
fragment (空)
归类 URL:给「发到哪」
原串 urn:isbn:9787115351531
scheme urn
netloc (空)
path isbn:9787115351531
query (空)
fragment (空)
归类 URN:给名字
原串 /a/b.html
scheme (空,相对引用)
netloc (空)
path /a/b.html
query (空)
fragment (空)
归类 相对引用(路径跟当前页面)
原串 //cdn.example.com/lib.js
scheme (空,相对引用)
netloc cdn.example.com
path /lib.js
query (空)
fragment (空)
归类 相对引用(协议跟当前页面)
URI 是总称;URL 是「按位置找」的那一类,URN 是「按名字认」的那一类。
日常说的网址,几乎全是 URL。
第一条带 user:pw@ 和端口 8443——netloc 里全都有,但现代浏览器对带密码的 URL 基本只警告不采用。
urn:isbn:… 的 path 是 isbn:9787115351531,没有 netloc。
这一行最能说明「URN 不说位置」——它连主机都没有。
//cdn.example.com/lib.js 的 scheme 是空的,但 netloc 有值。
这叫协议相对引用,意思是「协议跟当前页面一样」。
现在不推荐用了,因为本地文件打开时它会变成 file://。
30 秒实验
- 给
urn:isbn:那条补一个?x=1,看urlsplit还认不认(会认,但没意义)。 - 试试
urlsplit(u'HTTP://EXAMPLE.COM/A'),看 scheme 和 host 会不会自动变小写(scheme 会, path 不会)。 - 写一个
#frag的地址,用http.client真发一次,在服务端打印收到的原始字节, 看 fragments 有没有出现。
常见误区
- 「URI 就是 URL」——URL 是 URI 的子集。URN 也是 URI。
- 「
#后面的内容会发给服务器」——不会,只在浏览器本地用。 - 「相对路径和绝对路径一样」——
b.html依赖当前目录,/b.html依赖站点根。
自测三问(点开对答案)
1. URI、URL、URN 三者的关系? —— URI 是总称;URL 按位置定位,URN 按名字标识,两者都是 URI 的子集。 2. URL 的五个部件里,哪个不会发给服务器? —— `fragment`(`#` 之后的部分)。它只在客户端使用。 3. `//cdn.example.com/x.js` 的 scheme 是什么? —— 没有 scheme,叫协议相对引用,实际协议跟当前页面一致。部件认全了。下一节把这些部件拆到字节层面,看中文怎么变成百分号。
- ☐ (本节完,下一节 1.7.2 URI格式)
相关笔记
- 21 课 · Web技术原理(浏览器怎么解析与加载资源)
- 📘 图解HTTP · 索引