URL 是网页在网上的门牌号,它由七块拼成;其中最要紧的"域名"那一块,又是一串从右往左、一级比一级大的层级——这套层级叫 FQDN。
上一篇说浏览页面第一步是"报地址",并且强调地址必须精确。这一篇就把这个地址拆开,一块块看它是什么。上一篇还留了一句话——"门牌可能难看,但它精确"——精确体现在哪,读完这一篇就清楚了。地址里的域名怎么变成机器认得的 IP,前一门课讲过(网络的电话簿),本篇只讲"地址本身怎么拼",不重复那一段。
一、一个 URL 由七块拼成
拿一个"要素最全"的地址来开刀:
https://[email protected]:8443/shop/item?id=42&sort=asc#reviews
它看着乱,其实七块各管一件事,顺序固定、分隔符固定:
| 块 | 值 | 干什么用 |
|---|---|---|
| scheme | https | 用什么协议去取 |
| userinfo | user | 身份(早已不推荐写在这里) |
| host | www.example.co.jp | 去哪台机器 |
| port | 8443 | 敲哪扇门(不写就用默认) |
| path | /shop/item | 要机器上的哪一份 |
| query | id=42&sort=asc | 附带的条件 |
| fragment | reviews | 页面内部的位置 |
记住分隔符,就能一眼读地址:
://之前是协议,之后开始是"去哪儿"@之前是身份(今天几乎用不到):后面跟端口,/后面开始是路径?之后是条件,#之后是页面内部的位置
二、两个最容易忽略的细节
第一,port 处通常什么都没有。 因为每种协议都有自己的默认门牌号——http 默认 80,https 默认 443。不写就等于用默认。所以 https://example.com 和 https://example.com:443 是同一个地方。只有用了非默认端口(比如自己搭的测试服务器 8080),才必须写出来。
第二,# 后面那一段根本不会发给服务器。 它是给浏览器自己看的——用来在已经打开的页面里滚到某个位置。换句话说,a.html#x 和 a.html#y 从服务器那儿取回来的是同一份文件,只是滚到的地方不同。这也是为什么单页应用(比如文档站)能靠 # 切换不同的"页面",却不用每次都请求服务器。
三、域名那一块:从右往左,一级比一级大
host 那一段(www.example.co.jp)看着像一串单词,其实是一片分层结构。读它的方向是从右往左:
| 层 | 值 | 是什么 |
|---|---|---|
| 主机名(最左,最具体) | www | 这台机器在这家公司里的名字 |
| 注册的机构名 | example | 这家公司注册的名字 |
| 类别 | co | 这一级表示"公司" |
| 顶级域(最高一级) | jp | 属于哪个国家或类别 |
为什么从右往左读? 因为越往右越稳定、越大。最右边的 jp 是国别(日本),往左 co 是类别(公司),再往左 example 是具体哪一家,最左边的 www 是这家公司的某台机器。
这样设计的好处是"分权":管 jp 的机构只需要知道 co.jp 下面有哪些注册的名字,不用管每家内部怎么再分——每一级只负责自己那一层。这就是域名能扩展到全球的原因。
写全的这套名字,正式叫 FQDN(完全限定域名)。规矩上有两个上限:整串最长 255 个字符,每一层最长 63 个字符。
四、动手 Demo:把一个 URL 拆开
下面这个 Demo 用几行代码,把上面那个地址真拆一遍,再把域名逐层列出来。
def parse(u):
scheme = u.split("://")[0]
rest = u.split("://", 1)[1]
frag = rest.split("#", 1)[1] if "#" in rest else ""
rest = rest.split("#", 1)[0]
query = rest.split("?", 1)[1] if "?" in rest else ""
rest = rest.split("?", 1)[0]
hp = rest.split("/")[0]
return scheme, hp, rest[len(hp):] or "/", query, frag
print(parse("https://[email protected]:8443/shop/item?id=42&sort=asc#reviews"))
实跑输出:
--------------------------------------------------------------------
D4 什么是 URL:拆开看,它是七块拼起来的
--------------------------------------------------------------------
拿一个最复杂的例子开刀:
https://[email protected]:8443/shop/item?id=42&sort=asc#reviews
----------------------------------------------------------------------------------------
块 值 干什么用
----------------------------------------------------------------------------------------
scheme https 用什么协议去取
userinfo user 身份(早已不推荐写在这里)
host www.example.co.jp 去哪台机器(域名)
port 8443 敲哪扇门(不写就用默认)
path /shop/item 要机器上的哪一份
query id=42&sort=asc 附带的条件
fragment reviews 页面内部的位置(不发去服务器)
其中 host 那一块,本身又是一串层级——域名从右往左,一级比一级大:
www (主机名,最左,最具体)
example (注册的机构名)
co (类别)
jp (顶级域,最高一级)
这个主机名一共 4 层,写全了就称为 FQDN(完全限定域名)。
规则上说:整串最长 255 字符,每一层最长 63 字符。
非英文域名要先转成 punycode 才能上路,例如 cafe.com 会变成 xn--caf-dma.com。
读这个输出:最该记住的是最后两行。非英文域名不能直接上路——因为域名系统只认英文和数字,所以中文、日文、带重音的域名要先转成一种叫 punycode 的写法(开头是 xn--)。你在地址栏里看到的是好读的样子,实际去解析的是转出来那串。
五、⚠️ 2026 现状
教材 2024 年出版,URL 的规矩今天有一处重要的正名:
- "URL 还是 URI"这个老问题,官方已经给了答案。早年的标准(RFC 3986)里,URI 是总称、URL 是其中"能定位"的一种。但浏览器真正实现的那份标准(WHATWG 的 URL 标准)明确只用 URL 这个词,理由是区分 URI 和 URL 对实际工作没有帮助、反而让人糊涂。所以今天日常说"网址 = URL"完全正确,只有在读正式协议文档时才会碰到 URI。
#那一块成了前端的重要工具。前面说过它不发去服务器——今天单页应用大量利用这一点,在浏览器里"假装"切换页面,不重新请求服务器。- 默认端口这条规矩也在帮你省事。配服务器时若把 HTTPS 换到别的端口,用户就必须写出来——所以绝大多数网站宁可老老实实用 443。
30 秒实验
随便打开一个网页,把地址栏里的地址抄下来,做三件事:
- 找分隔符:找到
://、?、#,各划一条线,看看哪一段是哪一块。 - 看有没有端口:你会发现通常没有——那就说明它用的是默认端口(http 是 80、https 是 443)。
- 看域名:看最右边那一层是什么(
com、cn、jp……),再往左一层,读出"这是哪个国家的哪一类机构"。
然后想一想:如果这一页里点了另一个内部链接,地址里哪几块变了、哪几块没变?
常见误区
-
错误:地址里写了
#something,服务器就会收到它。——纠正:#后面那一段从来不会发给服务器。它是浏览器自己用的,用来在页面内定位。所以从服务器的角度看,a#x和a#y是同一个请求——这也是它能被前端拿来做"假翻页"的原因。 -
错误:域名是从左往右读的,
www最大。——纠正:正好相反,从右往左读、一级比一级大。最右边是顶级域(jp),最左边是具体的主机名。记反了会导致你看不懂"为什么改个公司名要动中间那一段"——因为注册的是中间那段,www只是它底下的一台机器。 -
错误:URL 就这样用吧,改了也没什么。——纠正:地址是门牌,改了就找不到了。网站改版把旧地址一改,别人收藏的链接、搜索引擎记的地址全部失效。所以正规做法是旧地址自动跳转到新地址——这也是为什么 URL 一旦发布,通常就不再改动。
-
错误:中文域名很好,直接写就行,不用管什么 punycode。——纠正:好写不等于好解析。域名系统只认英文和数字,中文域名必须转成
xn--开头的 punycode 才能实际使用。你在地址栏里看到中文,是浏览器替你转的——直接拿它去别的程序里用,往往就行不通。
自测三问(点开对答案)
1. `https://shop.example.com` 和 `https://shop.example.com:443/` 是同一个地方吗? —— **是**。`https` 的默认端口就是 443,不写等于用默认;路径不写时默认是 `/`。**所以这两个地址指向同一个资源**。理解这一点,你在配置服务器和排错时就不会被"地址看起来不一样"骗到。 2. 为什么域名要从右往左读,一层一级往上? —— 因为**越往右越稳定、越大**:`jp` 是国别,全日本共用;`co` 是类别;`example` 才是具体哪一家。这样设计让**每一级机构只负责自己那一层**——管 `jp` 的不需要知道日本每家公司内部怎么分。**分层是为了分权,分权是为了能扩展到全球**。 3. 单页应用靠什么做到"切换页面却不重新请求服务器"? —— 靠 **`#` 那一块**。因为 `#` 后面的内容**根本不会发给服务器**,所以浏览器可以在不发起新请求的情况下,根据它来改变页面上显示的内容。**代价是真正的地址(`?` 之前的那些)没变**,所以搜索引擎收录时可能碰到麻烦——这也是前端工程师要专门处理的问题。- ☐ 下一节(1-5 Web服务器的外观与内部结构:Linux、Windows Server、UNIX系统)
相关笔记
- 浏览Web页面 —— 上一篇:报地址是浏览的第一步
- Web服务器的外观与内部结构 —— 下一篇:门牌背后的那台机器长什么样
- 网络的电话簿(域名解析、主机名、DNS) —— 域名怎么变成 IP
- Web网站的地址(URL) —— 网络课里对 URL 的另一段讲述
- 🕸️ Web技术原理 · 索引 —— 全课路线图