首先釐清一個觀念:
資源 (resource),是對一實體集合的『概念』映射 (且允許空集合),
而 不是 針對特定時間點的『實體本身』。
例如:
https://example.org/users/jason/
透過這個 URI 能獲取 使用者 jason 的資料。
然而:
資料可能會更新、修改 或變更表示方式,
上星期 跟 現在 看到的結果或許不一樣 !
這個 URI 對映 (mapping) 的 資源,
是 『jason 個人資料』 這個 概念,
而非 『上星期』看到的那個『特定檔案』❗️
這個小小的觀念卻是 Web 架構的 關鍵特性 (key features) !
在說明他帶來的好處之前,得先知道什麼是 表示 (representation)。
目錄
表示 (representation)
沿著上述例子:
https://example.org/users/jason/
我們訪問此 URI (發出請求),並得到了一個網頁 (HTML document):
URI 對映的是一個 資源,資源 可以是任何東西,
而 資源 (resource),是對一實體集合的『概念』映射 (而非特定檔案)。
這個網頁 (HTML Document),
不過是『jason 個人資料』 這個 概念,其中一種 表示方式 (representation)。
一樣的概念,我們可以用 JSON 表示:
{
"id": 9487,
"name": "Jason",
"speciality": "sleep",
"gender": "male",
"blog": "NotFalse 技術客",
"blog_url": "https://notfalse.net"
}
也可以用 XML 表示 (或其它任意方式):
<id>9487</id>
<name>Jason</name>
<speciality>sleep</speciality>
<gender>male</gender>
<blog>Jason Puzzle 中勝拼圖</blog>
<blog_url>https://notfalse.net</blog_url>
我們訪問一個 URI,得到的只是資源的其中一個 表示方式!
資源狀態 (Resource State)
表示 (representation) [rɛprɪzɛnˋteʃən],確切說為 資源 的 表示,
旨在透過協議容易傳達的格式 (位元組 bytes),並伴隨 元資料 (metadata),
以反映出 資源「現在」「過去」或「預期」的 『狀態 (state)』。
又譯為 表示方式、表徵、具象、表現層、表述、代表… (我看過至少 10 種 😲)
(系列文將以『表示 (方式)』做為主要翻譯,視上下文而定)
常用但不精確的說法是:
文件、檔案、HTTP 訊息實體 (entity)、實例 (instance) 或 變體。
元資料 (meatadata)
元資料 (metadata),或稱 元數據、中介資料,指的是:
為描述其他資料資訊的「資料」
就像一本『書』的資訊是內文,而元資料包括:「出版社、作者、ISBN...」;
一個『影像』,其元資料包括:「影像格式、解析度、建立時間...」。
表示 (representation) 的 元資料 (metadata),通常包含了:
- 內容種類 (Content-Type)
- 內容編碼 (Content-Encoding)
- 內容語言 (Content-Language)
- 內容位置 (Content-Location)
- …
詳見 (3-2) 表示 — Content-Type, Content-Encoding。
資源實作 (Resource Implementation)
表示 (representation) 反映出 資源「現在」「過去」或「預期」的 『狀態 (state)』,
而將 資源 (resource) 與 表示 (representation) 產生關連的方法 (a means of associating),
即為 資源實作 (Resource Implementation)。
以 程式語言 為例,
資源 (resource) 是一 抽象 的 概念性映射 (conceptual mapping),
因此須對其 (資源映射) 進行 實作 (implements):
interface Resource {
Set<Representation> mapping();
}
同一資源,可能被提供或生成多種 表示 (representation),也可能是空集合,
源伺服器 (origin server) 需維護 資源標識符 — URI,
所對映的每個資源的 表示集合 之實作。
最後,HTTP 以 統一介面 (uniform interface),供 Web 元件之間 (e.g., Client、Server),
傳輸 (transfer) 與 操作 (manipulate) 表示 (representation),藉此達到與資源的互動,
為 REST 架構風格中 統一介面 的四個約束之一 :
以表示來操作資源 (manipulation of resources through representations)
這裡不討論如何實作資源映射 (可能是樹的深度走訪、雜湊表),
而是著重於 URI 與 資源實作 的關係與種類。
基於檔案與路徑名稱
(Based on File and Path Names)
一個廣泛的做法:
將 統一資源辨識符 (URI) 對映:
遠端檔案系統 (remote file system) 的檔案、路徑名稱,
並將那些檔案的 內容副本 視為 表示 (representation) 。
譬如,某個 源伺服器 (Origin Server) 的『files』目錄底下,
有許多資料夾 (Documents、Downloads、Music…),
其中 『Pictures』資料夾內,有一些動物的圖片 (xxx.png):
Server 將 URI 映射 (mapping) 至此目錄,
要訪問它們,只需打上相對應的網址,
有如在本機操作一樣簡單:
然後:
你會看到自己
開玩笑的~噗 🐽
我要說的是:
Server 不會因為回應給你,自己的小豬圖片就沒了,
而是 傳輸 (transfer) 一份 『副本』 給你,
且透過『PNG 影像』這種 表示 (representation) 呈現,這就是 — 內容副本。
這裡有個小陷阱:
儘管 URI 對映於檔案系統,不代表只有一種表示方式 !
Origin Server 也可能配置為:
將 Client 請求做為輸入,執行運算後,
將 表示 (representation) 輸出,而非直接傳輸檔案!
舉個極端的例子:
在小豬 URI 的後方,加入查詢 (query):
?width=2x
你可能看見,兩倍大的小豬 🐷 !
[註2]:
當然,Orign Server 必須配置好相關設定 (ex: 訪問權限、路由),
否則會產生一些問題:
- 重要資訊 (ex: 配置檔、密碼、憑證…) 可能曝光
- 目錄結構,可能淪為攻擊的依據
- …
基於概念
(Based on Concept)
當然,更多的應用,不只基於檔案系統,
URI 對映於抽象概念,使源伺服器 (Origin Server) 能 動態產生 表示,
以反射目標資源即時的狀態。
例如:
資料庫查詢結果的視圖、內容物件的樹狀結構、其他資訊系統的閘道,
或如上例,將 Client 請求做為輸入執行,並將 表示 (representation) 輸出。
基於概念 vs. 基於檔案
基於概念 (Based on Concept) 才是 URI 的設計理念,
應把 基於檔案 (Based on File) 視做其 子集 (subset),因為:
資源並非 儲存物件 (storage object)。
基於檔案 (Based on File) 的 URI 映射 (mapping) 方式 能夠實現,
僅是因為「檔案」擁有一組固定的語意,且容易被複製。
儘管如此,將那些已知的資源 映射於 靜態表示 (檔案),
能 降低延遲、利於 負載平衡 (load balancing),並減輕 源伺服器 (origin server) 的負擔,
基於檔案 (Based on File) 仍有其 必要性。
總而言之:
唯有 Origin Server 必須知道,
每個 資源辨識符 (Resource Identifier) — URI,需對映何種實作 (implementation),
每種實作方式該如何選擇、傳輸/轉移 (transfer) 目標資源的 表示 (representation)。
在《HTTP 資源、表示、URI》中有 6 則留言
很赞的文章!就是基于概念 (Based on Concept) 这一块不太明白您的意思,假如用户通过浏览器访问某个基于概念的 URI,那么对应的服务器是如何返回响应的呢?是将已有的档案动态组合,以特定的格式返回响应吗?抱歉,我想不出来一个具体的例子,你能提供一个吗?谢谢。
非常感謝 😆!
這裡我以 GitHub 來舉例說明,每個「使用者 (users)」可以有很多「倉庫/儲存庫 (repositories)」,因此,當我想檢視「使用者 JS-Zheng」的「binary-tree 倉庫」,可以檢視此 URI: https://github.com/JS-Zheng/binary-tree
這種 URI 即是以很直覺 (概念) 的方式告訴我們「哪個 User」和「哪個倉庫」,而非這種意味不明的 URI: https://github.com/!@#abc,當然,這不意味著 「Server 的根目錄中,有一個資料夾叫作 JS-Zheng,且裡面有一個 binary-tree 的 html 檔案」。
為了實現具意義性的 URI 設計,首先,Server 可能得使用 Rewrite 模組,以將 /JS-Zheng/binary-tree 對映到其他路徑或程序。可能單純是個 HTML 文件,也可能是 PHP, JSP… 等。另外,Server 能做的設定遠不如此,還能根據 HTTP 訊息,請求 URL, 副檔名, 時間, IP, 快取是否存在…等進行其他配置,以決定如何回應 Client。
關於 GitHub 的 URI 設計可以參考他們的 API:
https://developer.github.com/v3/
關於 rewrite 模組的設定,以 Apache 和 Nginx 為例:
https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html
以上,希望能幫到您 😇
感谢你耐心的回答。
我最初只关注了 URI 映射 (mapping) 的实现,没考虑到命名风格。看了一些关于 RESTful URI 的文章,算是有了个大致的了解了。
很高興能幫到您 😁
哇….要是沒有這一系列的HTTP教學的話我可能永遠學不會…對我這種完全沒任何經驗的初學者真的是學到了很多呢!!真的是非常的感謝!!(PS.元資料那個標題的英文是不是打錯了啊?上面寫meatadata可是下面都是metadataㄟ?)
【资源】的现在、过去、预期的这三个状态如何来理解呢?