HTTP

HTTP 請求方法 (Request Method)

(2-3) URI 設計 (URI Design) 提到,
HTTP 其中一個設計目標是:

分離『 資源辨識 (resource identification) 』 與 『 請求語意 (request semantics)

 
HTTP 請求方法 (Request Method)
是整個請求語意最主要的來源。
 
請求的 目標 (target) 是 資源 (resource),
而 請求方法 (Method) 則指出:

Client 發出此請求的 目的 (purpose) 與 期望的結果。

 


 

請求方法 (Request Method)

若 資源 (名詞) 是顆蘋果,到底是要 吃它? 削它? 煮它?
必須給他一個 『動詞』,來指名對它的操作。

HTTP 最初被設計為 分散式物件系統 (distributed object systems) 的使用介面,
請求方法 被設想為將 語意 (semantics) 應用於 目標資源。

 
一個理想的做法:

將請求方法 做為 動詞 (Method as Verb)

 

操作抽象 (Manipulating Abstraction)

(2-2) 資源、表示、URI 所述:

URI 對映的是一個 資源資源 可以是任何東西,
一個資源 (resource),是對映 (mapping) 到實體集合的『概念』(而非特定檔案)。

 
問題是:

使用者如何存取、操作 或 傳輸 "概念"?

 
Ans:

將被操作的對象,定義為 目標資源 的 表示 (representation),而非資源本身。

 
HTTP 以 統一介面 (uniform interface),供 Web 元件之間 (e.g., Client、Server),
傳輸 (transfer)操作 (manipulate) 表示,藉此達到與資源的互動。
 
表示 狀態 傳輸 (Representational State Transfer, REST)
於 統一介面 中,最重要的 介面約束

表示 (representation) 來操作資源。
manipulation of resources through representations.

 
Client 被限制在 操作表示,而非 直接尋訪 資源的內部實作 (e.g., server-side 閘道、資料庫、腳本),
因此,權威機構 (authority) 可依所期望的 任何形式 實作資源,而不影響 Client,
詳見 (1-3) 統一介面 (uniform interface)
 

標準化方法 (standardized method)

然而,不像分散式物件,
HTTP 不可能為每種 資源 都定義一種 方法 (動詞),
做為 基於網路系統 的 統一介面 (uniform interface),必須提供更好的可見性 與 重用性
 
於是,HTTP 定義了 標準化方法 (standardized method)
意圖應用於 任何資源,都能具有 相同的語義 (儘管每個資源是否實作或允許):

GET 、 POST 、 PUT 、 DELETE 、
HEAD 、 CONNECT 、 OPTIONS 、 TRACE

 
所有一般用途 Server 必須支援 GET 與 HEAD 方法,
剩下的方法則為 可選的。
 
其意義分別為:

請求方法安全性冪等性可快取性描述
GETOOO傳輸 目標資源 目前的 表示 (representation)
HEADOOO與 GET 方法相同,但 Server 只傳輸 狀態行 以及 表頭部分
POSTXXO [註]對請求的 酬載 (payload),執行 特定 資源的 處理
PUTXOX以請求的 酬載 (payload),替換 目標資源 所有目前的 表示 (representations)
DELETEXOX移除 目標資源 所有目前的 表示 (representations)
CONNECTXXX建立 「藉由 目標資源 辨識的 Server」的 隧道 (tunnel)
OPTIONSOOX描述 目標資源通訊選項
TRACEOOX沿著 目標資源路徑 執行 訊息 loop-back 測試

 
[註]:
HTTP/1.1 規範中 POST 為可快取的,然實作上鮮少支援。
 
可以看到,請求方法 是操作 表示 (representation),而非直接尋訪資源的內部實作。
 
另外,請求方法 是 區分大小寫 (case-sensitive) 的,
按照慣例,標準化方法皆以 全大寫 US-ASCII 字母定義。
 


 

請求訊息 (Request Message)

在逐一介紹 請求方法 (request method) 前,
先快速複習 請求訊息 (Request Message)
 
(3-1) 訊息格式 (Message Format) 範例,
請求方法 (request method) 位於請求訊息的開頭,
欲使用其他 方法,只需更改 POST 之處:

POST /task?id=1 HTTP/1.1

Host: echo.paw.cloud Content-Type: application/json; charset=utf-8 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0 Connection: close Content-Length: 136

 

{ "status": "ok", "extended": true, "results": [ {"value": 0, "type": "int64"}, {"value": 1.0e+3, "type": "decimal"} ] }

 
 

無意義的 酬載主體 (訊息主體)

值得注意的是,
範例中,訊息主體 雖有實際的資料 — — 酬載 (payload):

{ "status": "ok", "extended": true, "results": [ {"value": 0, "type": "int64"}, {"value": 1.0e+3, "type": "decimal"} ] }

 
然而,對於許多 請求方法 (e.g., GETHEADDELETECONNECTTRACE):

酬載 (payload) 是 未定義的語意 (無意義的),
若硬要送出,「可能」使 Server 拒絕此請求。

 
事實上,排除 TRACE 方法 外,HTTP 並無 嚴格限制 「請求方法 不准攜帶 酬載」,
換句話說,只要 Server 支援,一樣能在 GET 訊息 附加酬載送出。
(儘管這是不建議的做法)
 

訊息主體 (Message Body) 在 請求訊息中 是否存在,
Content-LengthTransfer-Encoding 欄位作為信號;
而與 方法語意 無關,即使該方法 未定義 訊息主體的任何用途。

 
許多人誤將 請求方法 視為訊息主體是否存在酬載的依據。
 


 

方法屬性 (Method Properties)

標準化 (standardized) 與 延伸方法,
皆註冊於 網際網路號碼分配局 (IANA)
且必須定義 安全性 (Safe)冪等性 (Idempotent)
 
 

安全方法 (Safe Methods)

如果定義的方法語義本質上是 唯讀 (read-only) 的,則該請求方法被認為是 安全的:

對 目標資源 應用 安全方法,源伺服器 (origin server) 不會 有任何 狀態改變 (state change)

 
標準化方法 (standardized method) 中:

GET、HEAD、OPTIONS、TRACE 為 安全方法。

 
合理使用 安全方法 (safe method) 不應對原始服務器造成任何危害、資產損失或異常,
然而,這僅指 方法語意 與 資源的關係,無法確保 不會有 潛在 危害的 行為 實作。
 
例如,許多 Server 在每次回應完成後,都會附加 請求資訊 至 日誌 (log),
不考慮方法,若日誌儲存已滿且致 Server 當機,這也被視為 安全的
同理,在網絡上選擇廣告而發起的 安全請求 通常會對廣告帳戶的收費產生額外作用。
 
 

非安全方法 (Unsafe Methods)

(2-2) 資源、表示、URI

表示 (representation)
旨在透過協議容易傳達的格式,與伴隨著 元資料 (metadata)
以反映出 資源「現在」「過去」或「預期」的 『狀態 (state)』

 
若應用一請求方法,可能造成 狀態改變 (State Change),
即為 — 非安全方法 (e.g., 資源的新增、修改、刪除…)。
 
標準化方法 (standardized method) 中:

POST、PUT、DELETE、CONNECT 為 非安全方法。

 
區分 安全 與 非安全方法,是為了:

允許自動檢索程序 (爬蟲) 和 快取效能優化 (預先載入) 的執行,而不用擔心造成危害。

 
HTTP/1.1 並無規範 狀態改變時 的主通通知機制,
能透過如 觀察者 (Observer)發佈/訂閱 (Publish/Subscribe) …等模式,
並以 Ajax 或 類 Comet 架構 (e.g., EventSource) 實作非同步應用。
 

淺在危害實作 (Potentially Harmful Implementation)

然而,許多應用 違背了其安全屬性,
例如,基於 Web 的內容編輯軟體,
通常在 URI 的 查詢參數 (query parameter) 中指出行為動作,並送出 GET 請求。
(e.g., https://example.com?page=3&action=delete)
 

 
這不僅是 不良地 (2-3) URI 設計 (URI 不應包含動詞),
如上所述,GET、HEAD、OPTIONS、TRACE 為 安全方法
刪除」的行為帶來了 狀態的改變 (state change) (即 副作用),違反了 GET 的 安全性。
 
要注意的是:

狀態的改變 (state change) 是 狀態傳輸/轉移 (state transfer)... 狀態的改變 (state change) 是 狀態傳輸/轉移 (state transfer)... 狀態的改變 (state change) 是 狀態傳輸/轉移 (state transfer)...

 
詳見 (1-3) 統一介面 (Uniform Interface)
 
google-bot
 
違反方法的安全性,可能使一些自動化程序造成危害,
[爬蟲 (spider)、預先載入 (pre-fetching)、建構 搜尋索引 (search index), etc.]
曾看過有人如此設計 blog URI,經 Google 爬蟲後,一覺醒來文章都沒了 😂:

https://example.com?article=2&action=delete

 

資源擁有者 (e.g., Server) 有責任確保 請求方法 與其安全屬性定義一致。

 
此外,安全方法 讓 使用者代理 (user agent) 在處理潛在不受信任的內容時,
對自動使用的非安全方法 進行適當約束,
並讓 使用者 在請求之前,了解行為是否安全。
 
 

冪等方法 (Idempotent Methods)

如果對 Server 送出單個請求,與送出多個相同請求的預期 效果相同 (回應訊息不同),
則該請求方法被認為是 冪等/等冪 (idempotent) [aɪˋdɛmpətənt]
 
安全方法 (safe method) 相同,這僅指 方法語意 與 資源的關係。
 
例如,Server 可以單獨每個請求 記錄日誌 (log),保留修訂歷史記錄,
或為每個 冪等請求 實現其他副作用,
而非送出一萬筆冪等請求,卻只有一筆日誌記錄。
 
標準化方法 (standardized method) 中:

PUT、DELETE 與 安全方法 (GET、HEAD、OPTIONS、TRACE) 為 冪等方法。

 
區分 冪等 與 非冪等方法,是為了:

當 Client 接收 回應前,若發生通訊錯誤,
冪等方法 能被自動地重複送出,並確保效果相同。

 
 

可快取方法 (Cacheable Methods)

如果允許將 回應 (response) 保存,供未來 等效的請求 重複使用
以 減少回應時間 與 網路頻寬的消耗,增進效能,
則該請求方法被認為是 可快取的
 
詳見 (6-1) 快取 (Cache)
 
標準化方法 (standardized method) 中:

GET、HEAD 和 POST 為 可快取方法。

 
然而絕大多數實作中,只支援 GETHEAD

 
 

作者: 鄭中勝
喜愛音樂,但不知為何總在打程式 ? 期許能重新審視、整理自身所學,幫助有需要的人。

發表迴響