內容協商¶
內容協商是一種用來根據使用者端和伺服器端可處理的資源類型,來決定回傳給客戶端哪種類型的內容的機制。該機制可用來決定客戶端是想要 HTML 還是想要 JSON ,一個圖片是應該以 JPG 還是以 PNG 格式回傳,或者支持哪種類型的壓縮方法等。這些決策是透過分析四個不同的請求頭,而這些請求頭里支持多個帶有優先級的值選項。手動對這些值選項進行優先級配對通常是比較傷腦的,因此 CodeIgniter 提供了 Negotiator
來處理以上的過程。
載入類別¶
你可以透過 Service 類別來手動載入一個該類別的實體:
$negotiate = \Config\Services::negotiator();
以上操作會獲取所有的請求實體並自動將其注入到 Negotiator (協商,下同)類別中。
該類別並不需要主動載入。而是透過請求的 IncomingRequest
實體來進行存取。儘管你並不能透過這一過程直接存取該實體,但你可以透過 negotiate()
方法來輕鬆的呼叫它的所有方法:
$request->negotiate('media', ['foo', 'bar']);
當透過該方法存取實體時,第一個參數是你需要匹配內容的類型,第二個是所支持的類型值構成的陣列。
協商¶
本節中,我們將討論四種可以用來協商的類型,並展示如何透過上述兩種方法來進行內容協商。
媒體¶
第一層首先要看的就是「媒體」協商。該協商方式是透過 Accept 請求頭進行的,並且是可用的請求頭中最為複雜的類型之一。一個常見的例子就是使用者端告訴伺服器端其所需要的資料格式,而這種操作在 API 中最為常見。例如,一個使用者端可能從一個 API 端點請求以 JSON 編碼的資料:
GET /foo HTTP/1.1
Accept: application/json
該伺服器需要提供一個支持該內容類型的列表。在這個例子中,API 可能需要回傳像原生 HTML ,JSON 或者是 XML 格式的資料。而該列表應根據使用者端偏好的順序回傳:
$supported = [
'application/json',
'text/html',
'application/xml'
];
$format = $request->negotiate('media', $supported);
// 或是
$format = $negotiate->media($supported);
在這個例子中,使用者端和伺服器端的協商一致,將資料以 JSON 的格式回傳,因此 『json』 就會從協商方法中回傳。預設情況下,如果沒有配對到,在 $support 陣列中的第一個元素就會被回傳。儘管在某些情況下,你可能會強制要求伺服器端嚴格得匹配格式。因此如果你將 true
作為最後的參數傳入時,在配對不到時就會回傳空字串:
$format = $request->negotiate('media', $supported, true);
// or
$format = $negotiate->media($supported, true);
語言¶
另一個常見的用法就是決定回傳內容的語言。如果你執行的是一個單語言網站,該功能顯然並沒有什麼影響。但是如果對於那些提供多語言內容的網站來說,該功能就會變得非常有用,基於瀏覽器將通常會在 Accept-Language
請求頭中發送偏好的語言類型:
GET /foo HTTP/1.1
Accept-Language: fr; q=1.0, en; q=0.5
在這個例子中,瀏覽器偏好法語,並次偏好英語。如果你的網站支持英語或德語,那麼你就會如下操作:
$supported = [
'en',
'de'
];
$lang = $request->negotiate('language', $supported);
// 或是
$lang = $negotiate->language($supported);
本例中,en 將作為當前語言回傳。如果沒有產生配對,就會回傳 $supported 陣列的第一個元素,因此該元素將會一直作為偏好語言。
編碼¶
Accept-Encoding
請求頭包含了使用者端所期望接收到的字符集,用於確定使用者端支持哪種類型的壓縮方式:
GET /foo HTTP/1.1
Accept-Encoding: compress, gzip
你的 web 伺服器將會定義可以使用的壓縮類型。某些伺服器,例如 Apache ,只支持了 gzip:
$type = $request->negotiate('encoding', ['gzip']);
// 或是
$type = $negotiate->encoding(['gzip']);
想了解更多的話,請查閱 維基百科.
字符集¶
所期待的字符集類型會透過 Accept-Charset
請求頭來傳值:
GET /foo HTTP/1.1
Accept-Charset: utf-16, utf-8
預設情況下,如果沒有配對到的話就會回傳 utf-8:
$charset = $request->negotiate('charset', ['utf-8']);
// 或是
$charset = $negotiate->charset(['utf-8']);