HTTP

HTTP 資源、表示、URI

首先釐清一個觀念:
資源 (resource),是對一實體集合的『概念』映射 (且允許空集合),
不是 針對特定時間點的『實體本身』。
 
例如:

https://example.org/users/jason/

透過這個 URI 能獲取 使用者 jason 的資料。
 
然而:

資料可能會更新、修改 或變更表示方式,
上星期 跟 現在 看到的結果或許不一樣 !

 
這個 URI 對映 (mapping) 的 資源
是 『jason 個人資料』 這個 概念
而非 『上星期』看到的那個『特定檔案』❗️
 
這個小小的觀念卻是 Web 架構的 關鍵特性 (key features) !
在說明他帶來的好處之前,得先知道什麼是 表示 (representation)
 


 

表示 (representation)

沿著上述例子:

https://example.org/users/jason/

 
我們訪問此 URI (發出請求),並得到了一個網頁 (HTML document):
jason-html
 
 
 

因此我們得到了這個 資源 ?

 

錯 !!

 

我們得到的只是這個資源的 其中一種『表示方式』!

 

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) 輸出。
web-resources
 
 

基於概念 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》中有 7 則留言

  1. 很赞的文章!就是基于概念 (Based on Concept) 这一块不太明白您的意思,假如用户通过浏览器访问某个基于概念的 URI,那么对应的服务器是如何返回响应的呢?是将已有的档案动态组合,以特定的格式返回响应吗?抱歉,我想不出来一个具体的例子,你能提供一个吗?谢谢。

    1. 非常感謝 😆!

      這裡我以 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

      以上,希望能幫到您 😇

      1. 感谢你耐心的回答。
        我最初只关注了 URI 映射 (mapping) 的实现,没考虑到命名风格。看了一些关于 RESTful URI 的文章,算是有了个大致的了解了。

  2. 哇….要是沒有這一系列的HTTP教學的話我可能永遠學不會…對我這種完全沒任何經驗的初學者真的是學到了很多呢!!真的是非常的感謝!!(PS.元資料那個標題的英文是不是打錯了啊?上面寫meatadata可是下面都是metadataㄟ?)

  3. (define 资源A 2)
    (define 资源A 1)
    所以资源是名字,而表示是具体的内容
    或者资源是抽象数据类型,而表示是具体实现

發表迴響