URI & URL
URI,Uniform Resource Identifier,統一資源標識符。
URL,Uniform Resource Location,統一資源定位符。
URI 簡單來理解就是標識/定義了一個資源,而 URL 在定義/標識資源的同時還需要描述如何訪問到該資源。可以認為 URL 是 URI 的一個子集。
舉個例子:
公司里每個人都有一個內部唯一的花名,這個花名其實就可以認為是 URI,它對應了公司內部唯一的一個人(資源)。當我需要找這個人時,雖然我知道了花名(URI),但是並找不到他人,因為我不知道他的工位,這時候就需要知道他的工位號如 13B-11 ,工位號+花名其實就是一個 URL,它指定了一個人以及怎么找到這個人的位置。上述例子可能並不規范,但是感覺這樣比較容易理解區分。一般來說 URI 有一個通用的結構描述:
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]

其實現在我們不必刻意去區分 URI / URL / URN 。在 [RFC3986]上已經明確說明這個點:
Future specifications and related documentation should
use the general term "URI" rather than the more restrictive terms
"URL" and "URN".
fragment
主要資源是由 URI 進行標識,URI 中的 fragment 用來標識次級資源。我理解看來,fragment 主要是用來標識 URI 所標識資源里的某個資源。
在 URI 的末尾通過 hash mark(#)作為 fragment 的開頭,其中 # 不屬於 fragment 的值。
https://domain/index#L18
這個 URI 中 L18
就是 fragment 的值。這有哪些特殊的地方呢?
-
#
有別於?
,?
后面的查詢字符串會被網絡請求帶上服務器,而 fragment 不會被發送的服務器; - fragment 的改變不會觸發瀏覽器刷新頁面,但是會生成瀏覽歷史;
- fragment 會被瀏覽器根據文件媒體類型(MIME type)進行對應的處理;
- Google 的搜索引擎會忽略
#
及其后面的字符串。
針對以上幾點特性,分別介紹下 URI fragment 的應用。
特性 1 & 2 單頁面路由
針對 1、2 這兩個特性,目前主要的應用就是單頁面路由。具體原理簡單描述如下:JavaScript 提供了 location.hash
來操作當前 URI 的 fragment,同時提供了 Hashchange
事件監聽 fragment 的變化。利用這兩個 API 再結合上述特性 1、2 就可以實現一個簡單前端路由。具體流程如下圖:

修改 location.hash 值,觸發 hashchange 事件,JS 處理對應的邏輯,改變頁面 UI 實現頁面的跳轉,並在瀏覽器中產生歷史記錄。
特性 3 HTML 錨點
在 HTML 中比較常見的一個應用 —— 頁面內定位。在頁面中通過設置標簽的 id 屬性來定義錨點,從而實現錨點定位。實際上錨點定位的實現正是依賴了 fragment 的特性 3。如這個 URI https://domain/index.html#L18
,假設返回的文件類型是 text/html,則瀏覽器會讀取 URI’s fragment,然后在頁面中尋找 L18 這個錨點,並將頁面滾動到該錨點的位置。
因此我們當點擊 <a href="#top">top</a>
時,實際上處理過程是 URI 的 hash 發生變化,然后瀏覽器讀取新的 fragment,並尋找 DOM 中是否存在對應的錨點,將該錨點顯示到頁面中。在 MIME Type 為 HTML 或 XML 時,如https://domain/index.html#
這個 URI 中是空的 fragment,則瀏覽器默認顯示頁面的最頂端。
特性 4
特性4 其實是針對 hash 模式前端路由來說的一個缺點。因為 fragment 會被 Google 搜索引擎忽略掉,因此對於用 hash 模式前端路由的應用的 SEO 來說是很不友好的。不過 Google 給了一個方案,就是在 #
緊跟一個 !
,這樣Google 搜索引擎就會將這個 URI 進行轉換,如 https://domain/index.html#!L18
轉換后就成為了 https://domain/index.html?_escaped_fragment_=L18
。這樣搜索引擎就會攜帶上 URI’s fragment 直接去訪問這個 URI,開發者可以利用這個 trick 優化網站的 SEO。
小結
- fragment 對於 HTML 文檔來說就是頁面內的定位標識符,可以實現 HTML 頁面內的定位。當然瀏覽器針對不同類型的資源會有區分的處理 fragment;
- 利用 fragment 實現前端頁面無刷新修改 Brower’s URI;
- 根據搜索引擎規則,可以優化無刷新修改頁面的 SEO;