1. 程式人生 > >HTTP內容協商

HTTP內容協商

http

一個URL常常需要代表若幹不同的資源。例如那種需要以多種語言提供其內容的網站站點。如果某個站點有說法語的和說英語的兩種用戶,它可能想用這兩種語言提供網站站點信息。理想情況下,服務器應當向英語用戶發送英文版,向法語用戶發送法文版——用戶只要訪問網站主頁就可以得到相應語言的內容

  HTTP提供了內容協商方法,允許客戶端和服務器作這樣的決定。通過這些方法,單一的URL就可以代表不同的資源(比如,同一個網站頁面的法語版和英語版),這些不同的版本稱為變體。本文將詳細介紹內容協商

總括

  對於特定的URL來說,服務器可以根據一些原則來決定發送什麽內容給客戶端最合適。在有些場合下,服務器甚至可以自動生成定制的頁面。比如,服務器可以為手持設備把HTML頁面轉換成WML頁面。這類動態內容變換被稱為轉碼。這些變換動作是HTTP客戶端和服務器之間進行內容協商的結果

  共有3種不同的方法可以決定服務器上哪個頁面最適合客戶端:讓客戶端來選擇、服務器自動判定,或讓中間代理來選。這3種技術分別稱為客戶端驅動的協商、服務器驅動的協商以及透明協商

技術分享

客戶端驅動

  對於服務器來說,收到客戶端請求時只是發回響應,在其中列出可用的頁面,讓客戶端決定要看哪個,這是最容易的事情。很顯然,這是服務器最容易實現的方式,而且客戶端很可能選擇到最佳的版本(只要列表中有讓客戶端選擇的足夠信息)。不利之處是每個頁面都需要兩次請求:第一次獲取列表,第二次獲取選擇的副本。這種技術速度很慢且過程枯燥乏味,讓用戶厭煩

  從實現原理上來說,服務器實際上有兩種方法為客戶端提供選項:一是發送回一個HTML文檔,裏面有到該頁面的各種版本的鏈接和每個版本的描述信息,另一種方法是發送回HTTP/1.1響應時,使用300 Multiple Choices響應代碼。客戶端瀏覽器收到這種響應時,在前一種情況下,會顯示一個帶有鏈接的頁面,在後一種情況下,可能會彈出對話窗口,讓用戶做選擇。不管怎麽樣,決定是由客戶端的瀏覽器用戶作出的

  除了增加時延並且對每個頁面都要進行繁瑣的多次請求之外,這種方法還有一個缺點:它需要多個URL:公共頁面要一個,其他每種特殊頁面也都要一個。因此,比如說原始的請求地址是www.joes-hardware.com,Joe的服務器可能會回復某個頁面,該頁面裏面有到www.joes-hardware.com/english和www.joes-hardware.com/french的鏈接。如果客戶端想加書簽的話,是要加在原始的公共頁面上呢,還是加在選中的頁面上呢?如果用戶想把這個網站推薦給他的朋友,是告知www.joes-hardware.com這個地址好呢,還是只告訴他們講英語的朋友www.joes-hardware.com/english這個地址?

服務器驅動

  減少額外通信量的一種方法是讓服務器來決定發送哪個頁面回去,但為了做到這一點,客戶端必須發送有關客戶偏好的足夠信息,以便服務器能夠作出準確的決策。服務器通過客戶端請求的首部集來獲得這方面的信息

  有以下兩種機制可供HTTP服務器評估發送什麽響應給客戶端比較合適

  1、檢査內容協商首部集。服務器察看客戶端發送的Accept首部集,設法用相應的響應首部與之匹配

  2、根據其他(非內容協商)首部進行變通。例如,服務器可以根據客戶端發送的User-Agent首部來發送響應

  【內容協商首部集】

  客戶端可以用下面列出的HTTP首部集發送用戶的偏好信息

首部           描述
Accept           告知服務器發送何種媒體類型
Accept-Language      告知服務器發送何種語言
Accept-Charset      告知服務器發送何種字符集
Accept-Encoding      告知服務器采用何種編碼

  [註意]這些首部與實體首部非常類似。不過,這兩種首部的用途截然不同。實體首部集像運輸標簽,它們描述了把報文從服務器傳輸給客戶端的過程中必須的各種報文主體屬性。而內容協商首部集是由客戶端發送給服務器用於交換偏好信息的,以便服務器可以從文檔的不同版本中選擇出最符合客戶端偏好的那個來提供服務

  服務器用下面列出的實體首部集來匹配客戶端的Accept首部集

Accept首部          實體首部
Accept          Content-Type
Accept-Language     Content-Language
Accept-Charset      Content-Type
Accept-Encoding     Content-Encoding

  由於HTTP是無狀態的協議,表示服務器不會在不同的請求之間追蹤客戶端的偏好,所以客戶端必須在每個請求中都發送其偏好信息

  如果兩個客戶端都發送了Accept-Language首部,描述它們感興趣的語言信息,服務器就能夠決定發送www.joes-hardware.com的何種版本給哪個客戶端了。讓服務器自動選擇發送回去的文檔,減少了往返通信的時延,這種時延是客戶端驅動模型中無法避免的

  然而,假設某個客戶端偏好西班牙文,那服務器應當回送哪個版本的頁面呢?英語還是法語?服務器只有兩種選擇:猜測或回退到客戶端驅動模型,問客戶端選擇哪個。假如這個西班牙人碰巧懂一點英語,他可能會選擇英文頁面,這不是最理想的,但它能解決問題。在這種情況下,這個西班牙人需要有辦法傳達更多與其偏好有關的信息,也就是他的確對英語略知一二,在沒有西班牙語的時候,英語也行

  幸運的是,HTTP提供了一種機制,可以讓與這個西班牙人情況類似的客戶端更詳細地描述其偏好。這種機制就是質量值(簡稱q值)

  HTTP協議中定義了質量值,允許客戶端為每種偏好類別列出多種選項,並為每種偏好選項關聯一個優先次序。例如,客戶端可以發送下列形式的Accept-Language首部:

Accept-Language: en; q=0.5, fr; q=0.0 , nl; q=1.0, tr; q=0.0

  其中q值的範圍從0.0-1.0(0.0是優先級最低的,而1.0是優先級最高的)。上面列出的那個首部,說明該客戶端最願意接收荷蘭語(縮寫為nl)文檔,但英語(縮寫為en)文檔也行;無論如何,這個客戶端都不願意收到法語(縮寫為fr)或土耳 其語(縮寫為tr)的版本

  [註意]偏好的排列順序並不重要,只有與偏好相關的q值才是重要的

  服務器偶爾也會碰到找不到文檔可以匹配客戶端的任何偏好的情況。對於這種情況,服務器可以修改文檔,也就是對文檔進行轉碼,以匹配客戶端的偏好

【其他首部集】

  服務器也可以根據其他客戶端請求首部集來匹配響應,比如User-Agent首部。例如,服務器知道老版本的瀏覽器不支持JavaScript語言,這樣就可以向其發送不含有JavaScript的頁面版本

  在這種情況下,沒有q值機制可供査找“最近似”的匹配。服務器或者去找完全匹配,或者簡單地有什麽就給什麽,這取決於服務器的實現

  由於緩存需要盡力提供所緩存文檔中正確的“最佳”版本,HTTP協議定義了服務器在響應中發送的Vary首部。這個首部告知緩存,還有客戶端和所有下遊的代理,服務器根據哪些首部來決定發送響應的最佳版本

【Apache】

  下面概括了著名的Web服務器Apache是如何支持內容協商的。網站的內容提供者,比如說Joe要負責為Joe的索引頁面提供不同的版本。Joe還必須把這些索引頁面文件放在和站點相關的Apache服務器的適當目錄下。用以下兩種方式可以啟用內容協商

  1、在網站目錄中,為網站中每個有變體的URI創建一個type-map(類型映射)文件。這個type-map文件列出了每個變體和其相關的內容協商首部集

  2、啟用MultiViews指令,這樣會使Apache自動為目錄創建type-map文件

【使用type-map文件】

  Apache服務器需要知道type-map文件的命名規則。可以在服務器的配置文件中設置handler來說明type-map文件的後綴名。例如:

AddHandler type-map .var

  這行就說明了後綴是.var的文件就是type-map文件

  下面給出一個type-map文件示例

技術分享

  根據這個type-map文件,Apache服務器就知道要發送joes-hardware.en.html給請求英語版的客戶端,發送joes-hardware.fr.de.html給請求法語版的客戶端。Apache服務器也支持質量值

【使用MultiView】

  為了使用MultiView,必須在網站目錄下的access.conf文件中的適當小節(<Directory>、<Location>,或<Files>)使用OPTION指令來啟用它

  如果啟用了MultiView,而瀏覽器又請求了名為joes-hardware的資源,服務器就會査找所有名字中含有joes-hardware的文件,並為它們創建type-map文件。服務器會根據名字猜測其對應的內容協商首部集。例如,法語版的joes-hardware應當含有.fr

  另一種在服務器端實現內容協商的方法是使用服務器端擴展,比如微軟的動態服務器頁面(Microsoft’s Active Server Pages, ASP)

透明協商

  透明協商機制試圖從服務器上去除服務器驅動協商所需的負載,並用中間代理來代表客戶端以使與客戶端的報文交換最小化。假定代理了解客戶端的預期,這樣就可以代表客戶端與服務器協商,在客戶端請求內容的時候,代理已經收到了客戶端的預期

  為了支持透明內容協商,服務器必須有能力告知代理,服務器需要檢査哪些請求首部,以便對客戶端的請求進行最佳匹配。HTTP/1.1規範中沒有定義任何透明協商機制,但定義了Vary首部。服務器在響應中發送了Vary首部,以告知中間節點需要使用哪些請求首部進行內容協商

  代理緩存可以為通過單個URL訪問的文檔保存不同的副本。如果服務器把它們的決策過程傳給緩存,這些代理就能代表服務器與客戶端進行協商。緩存同時也是進行內容轉碼的好地方,因為部署在緩存裏的通用轉碼器能對任意服務器,而不僅僅是一臺服務器傳來的內容進行轉碼

【緩存與備用候選】

  對內容進行緩存的時候是假設內容以後還可以重用。然而,為了確保對客戶端請求回送的是正確的已緩存響應,緩存必須應用服務器在回送響應時所用到的大部分決策邏輯

  上面描述了客戶端發送的Accept首部集,以及為了給每條請求選擇最佳的響應,服務器使用的與這些首部集匹配的相應實體首部集。緩存也必須使用相同的首部集來決定回送哪個已緩存的響應

  下圖展示了涉及緩存的正確及錯誤的操作序列。緩存把第一個請求轉發給服務器,並存儲其響應。對於第二個請求,緩存根據URL査找到了匹配的文檔。但是,這份文檔是法語版的,而請求者想要的是西班牙語版的。如果緩存只是把文檔的法語版本發給請求者的話,它就犯了錯誤

技術分享

  因此,緩存也應該把第二條請求轉發給服務器,並保存該URL的響應與“備用候選”響應。緩存現在就保存了同一個URL的兩份不同的文檔,與服務器上一樣。這些不同的版本稱為變體(variant)或備用候選(alternate)。內容協商可看成是為客戶端請求選擇最合適變體的過程

【Vary 首部】

  這裏是瀏覽器和服務器發送的一些典型的請求及響應首部

技術分享

  然而,如果服務器的決策不是依據Accept首部集,而是比如User-Agent首部的話,情況會如何?這不像聽起來這麽極端。例如,服務器可能知道老版本的瀏覽器不支持JavaScript語言,因此可能會回送不包含JavaScript的頁面版本。如果服務器是根據其他首部來決定發送哪個頁面的話,緩存必須知道這些首部是什麽,這樣才能在選擇回送的頁面時做出同樣的邏輯判斷

  HTTP的Vary響應首部中列出了所有客戶端請求首部,服務器可用這些首部來選擇文檔或產生定制的內容(在常規的內容協商首部集之外的內容)。例如,若所提供的文檔取決於User-Agent首部,Vary首部就必須包含User-Agent

  當新的請求到達時,緩存會根據內容協商首部集來尋找最佳匹配。但在把文檔提供給客戶端之前,它必須檢査服務器有沒有在已緩存響應中發送Vary首部。如果有Vary首部,那麽新請求中那些首部的值必須與舊的已緩存請求裏相應的首部相同。因為服務器可能會根據客戶端請求的首部來改變響應,為了實現透明協商,緩存必須為每個已緩存變體保存客戶端請求首部和相應的服務器響應首部,參見下圖

技術分享

  如果某服務器的Vary首部看起來像下面這樣,大量不同的User-Agent和Cookie值將會產生非常多的變體:

Vary: User-Agent, Cookie

  緩存必須為每個變體保存其相應的文檔版本。當緩存執行査找時,首先會對內容協商首部集進行內容匹配,然後比較請求的變體與緩存的變體。如果無法匹配,緩存就從原始服務器獲取文檔

轉碼

  我們已經討論了一個機制,該機制可以讓客戶端和服務器從某個URL的一系列文檔中挑選出最適合客戶端的文檔。實現這些機制的前提是,存在一些滿足客戶端需求的文檔——不管是完全滿足還是在一定程度上滿足

  然而,如果服務器沒有能滿足客戶端需求的文檔會怎麽樣呢?服務器可以給出一個錯誤響應。但理論上,服務器可以把現存的文檔轉換成某種客戶端可用的文檔。這種選項稱為轉碼

  下面列出了一些假設的轉碼

技術分享

轉換之前             轉換之後
HTML文檔              WML文檔
高分辨率圖像            低分辨率圖像
彩色圖像              黑白圖像
有多個框架的復雜頁面        沒有很多框架或圖像的簡單文本頁面
有Java小應用程序的HTML頁面    沒有Java小應用程序的HTML頁面
有廣告的頁面            去除廣告的頁面

技術分享

  有3種類別的轉碼:格式轉換、信息綜合以及內容註入

【格式轉換】

  格式轉換是指將數據從一種格式轉換成另一種格式,使之可以被客戶端査看。通過HTML到WML的轉換,無線設備就可以訪問通常供桌面客戶端査看的文檔了。通過慢速連接訪問Web頁面的客戶端並不需要接收高分辨率圖像,如果通過格式轉換降低圖像分辨率和顏色來減小圖像文件大小的話,這類客戶端就能更容易地査看圖像比較豐富的頁面了

  格式轉換可以由內容協商首部集來驅動,但也能由User-Agent首部來驅動。註意,內容轉換或轉碼與內容編碼或傳輸編碼是不同的,後兩者一般用於更高效或安全地傳輸內容,而前兩者則可使訪問設備能夠査看內容

【信息綜合】

  從文檔中提取關鍵的信息片段稱為信息綜合(information synthesis),這是一種有用的轉碼操作。這種操作的例子包括根據小節標題生成文檔的大綱,或者從頁面中刪除廣告和商標

  根據內容中的關鍵字對頁面分類是更精細的技術,有助於總結文檔的精髓。這種技術常用於Web頁面分類系統中,比如門戶網站的Web頁面目錄

【內容註入】

  前面描述的兩類轉碼通常會減少Web文檔的內容,但還有另一類轉換會增加文檔的內容,即內容註入轉碼。內容註入轉碼的例子有自動廣告生成器和用戶追蹤系統

  設想一下,一個能往途經的每個HTML頁面中自動添加廣告的廣告植入轉碼器是多麽的誘人,當然也很煩人。這類轉碼操作只能動態進行——它必須即時添加與當前的特定用戶有關,或針對特定用戶的廣告。也可以構建用戶追蹤系統,在頁面中動態增加內容,用於收集用戶査看頁面和客戶端瀏覽方式的統計信息

【轉碼與靜態預生成的對比】

  轉碼的替代做法是在Web服務器上建立Web頁面的不同副本,例如一個是HTML,一個是WML;一個圖像分辨率高,一個圖像分辨率低;一個有多媒體內容,一個沒有。但是,這種方法不是很切合實際,原因很多:某個頁面中的任何小改動都會牽扯很多頁面,需要很多空間來存儲各頁面的不同版本,而且使頁面編目和Web服務器編程(以提供正確的版本)變得更加困難。有些轉碼操作,比如廣告插入(尤其是定向廣告插入),就不能靜態實現——因為插入什麽廣告和請求頁面的用戶有關

  對單一的根頁面進行即時轉換,是比靜態的預生成更容易的解決方案。但這樣會在提供內容時增加時延。不過有時候其中一些計算可以由第三方進行,這樣就減少了Web服務器上的計算負荷——比如可以由代理或緩存中的外部Agent完成轉換

  下圖顯示了在代理緩存中進行的轉碼

技術分享


HTTP內容協商