Apache HTTPD支持HTTP/1.1規(guī)范中描述的內(nèi)容協(xié)商。它可以根據(jù)瀏覽器提供的媒體類型,語言,字符集和編碼首選項(xiàng),選擇資源的最佳表示形式。它還實(shí)現(xiàn)了一些功能,可以更智能地處理來自發(fā)送不完整協(xié)商信息的瀏覽器的請求。
內(nèi)容協(xié)商由mod_negotiation模塊提供,該模塊默認(rèn)編譯。
關(guān)于內(nèi)容協(xié)商資源可以以多種不同的表示形式提供。例如,它可能以不同語言或不同媒體類型或組合形式提供。選擇最合適選擇的一種方法是為用戶提供索引頁面,然后讓他們選擇。但是,服務(wù)器通??梢宰詣舆x擇。這是可以做到的,因?yàn)闉g覽器可以在每個請求中發(fā)送有關(guān)他們喜歡的表示形式的信息。例如,如果可能的話,瀏覽器可以表明它希望看到法語信息,否則會發(fā)送英語信息。瀏覽器通過請求中的標(biāo)題指示其首選項(xiàng)。僅請求法語的表示,那么瀏覽器將發(fā)送法語內(nèi)容信息。
Accept-Language: fr
Shell
請注意,只有在可以選擇表示時才會應(yīng)用此首選項(xiàng),并且這些首選項(xiàng)因語言而異。
作為更復(fù)雜請求的示例,此瀏覽器已配置為接受法語和英語,但更喜歡法語,并接受各種媒體類型,更喜歡HTML而不是純文本或其他文本類型,并且優(yōu)先選擇GIF或JPEG而不是其他媒體類型 ,但也允許任何其他媒體類型作為最后的手段:
Accept-Language: fr; q=1.0, en; q=0.5
Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1
Shell
httpd支持“服務(wù)器驅(qū)動的”內(nèi)容協(xié)商,如HTTP/1.1規(guī)范中所定義。它完全支持Accept,Accept-Language,Accept-Charset和Accept-Encoding請求標(biāo)頭。httpd還支持“透明”內(nèi)容協(xié)商,這是RFC 2295和RFC 2296中定義的實(shí)驗(yàn)性協(xié)商協(xié)議。它不支持這些RFC中定義的“功能協(xié)商”。
資源是由URI(RFC 2396)標(biāo)識的概念實(shí)體。像Apache HTTP Server這樣的HTTP服務(wù)器提供對其命名空間內(nèi)資源表示的訪問,每個表示形式為具有已定義媒體類型,字符集,編碼等的字節(jié)序列。每個資源可以關(guān)聯(lián)在任何給定時間使用零個,一個或多個表示。如果有多個表示可用,則該資源被稱為可協(xié)商的,并且其每個表示被稱為變體??赊D(zhuǎn)讓資源的變體的變化方式稱為協(xié)商的維度。
httpd的協(xié)商為了協(xié)商資源,需要向服務(wù)器提供有關(guān)每個變體的信息。這可以通過以下兩種方式之一完成:
使用類型映射(即*.var文件)明確命名包含變體的文件,或使用“MultiViews”搜索,服務(wù)器執(zhí)行隱式文件名模式匹配,并從結(jié)果中進(jìn)行選擇。
使用類型映射文件類型映射是與名為type-map的處理程序相關(guān)聯(lián)的文檔(或者,對于與舊的httpd配置的向后兼容性,MIME類型的應(yīng)用程序/x-type-map)。請注意,要使用此功能,必須在配置中設(shè)置一個處理程序,將文件后綴定義為type-map是最好的。
AddHandler type-map .var
Shell
在服務(wù)器配置文件中。
類型映射文件應(yīng)與其描述的資源具有相同的名稱,后跟擴(kuò)展名.var。在下面顯示的示例中,資源名為foo,因此類型映射文件名為foo.var。
此文件應(yīng)包含每個可用變體的條目; 這些條目由連續(xù)的HTTP格式標(biāo)題行組成。不同變體的條目由空行分隔??瞻仔性跅l目中是非法的。通常開始一個映射文件,其中包含整個組合實(shí)體的條目(盡管這不是必需的,如果存在則將被忽略)。示例映射文件如下所示。
此文件中的URI相對于類型映射文件的位置。通常,這些文件將與類型映射文件位于同一目錄中,但這不是必需的??梢詾榕c映射文件位于同一服務(wù)器上的任何文件提供絕對或相對URI。
URI: foo
URI: foo.en.html
Content-type: text/html
Content-language: en
URI: foo.fr.de.html
Content-type: text/html;charset=iso-8859-2
Content-language: fr, de
Shell
請注意,即使啟用了Multiviews,類型映射文件也將優(yōu)先于文件名的擴(kuò)展名。如果變體具有不同的源質(zhì)量,則可以通過媒體類型的“qs”參數(shù)指示,如此圖片(可用作JPEG,GIF或ASCII藝術(shù)):
URI: foo
URI: foo.jpeg
Content-type: image/jpeg; qs=0.8
URI: foo.gif
Content-type: image/gif; qs=0.5
URI: foo.txt
Content-type: text/plain; qs=0.01
Shell
qs值可以在0.000到1.000的范圍內(nèi)變化。請注意,永遠(yuǎn)不會選擇qs值為0.000的任何變體。沒有’qs’參數(shù)值的變量的因子為1.0。qs參數(shù)表示此變體與其他可用變體相比的相對“qs”,與客戶端的能力無關(guān)。例如,如果JPEG文件試圖表示照片,則該文件通常具有比ASCII文件更高的源質(zhì)量。但是,如果表示的資源是原始ASCII藝術(shù),那么ASCII表示將具有比JPEG表示更高的源質(zhì)量。因此,qs值特定于給定變體,具體取決于它所代表的資源的性質(zhì)。
MultiviewsMultiViews是一個每個目錄選項(xiàng),它可以在httpd.conf中的<Directory>,<Location>或<Files>部分中使用Options指令設(shè)置,或者在.htaccess文件中設(shè)置(如果正確設(shè)置了AllowOverride)。請注意,選項(xiàng)全部不設(shè)置MultiViews; 必須通過名字指定它。
MultiViews的效果如下:如果服務(wù)器收到/some/dir/foo的請求,如果/some/dir啟用了MultiViews,并且/some/dir/foo不存在,那么服務(wù)器會讀取尋找的目錄名為foo.*的文件,有效地偽造了一個類型映射,該映射命名所有這些文件,為它們分配相同的媒體類型和內(nèi)容編碼,如果客戶端通過名稱請求其中一個文件。然后,它會根據(jù)客戶的要求選擇最佳匹配。
如果服務(wù)器嘗試索引目錄,MultiViews也可能適用于搜索DirectoryIndex指令指定的文件。如果配置文件指定:
DirectoryIndex index
Shell
然后,如果兩者都存在,服務(wù)器將在index.html和index.html3之間進(jìn)行選擇。如果兩者都不存在,并且存在index.cgi服務(wù)器將運(yùn)行index.cgi。
如果在讀取目錄時找到的其中一個文件沒有mod_mime識別的擴(kuò)展名來指定其Charset,Content-Type,Language或Encoding,則結(jié)果取決于MultiViewsMatch指令的設(shè)置。此指令確定處理程序,過濾器和其他擴(kuò)展類型是否可以參與MultiViews協(xié)商。
協(xié)商方法在httpd從類型映射文件或目錄中的文件名獲得給定資源的變體列表之后,它會調(diào)用兩種方法之一來決定要返回的“最佳”變體(如果有)。為了使用httpd的內(nèi)容協(xié)商功能,沒有必要知道協(xié)商實(shí)際發(fā)生的任何細(xì)節(jié)。
有兩種協(xié)商方法:
服務(wù)器驅(qū)動協(xié)商 - 在正常情況下使用與httpd算法的服務(wù)器驅(qū)動的協(xié)商。httpd算法在下面更詳細(xì)地解釋。當(dāng)使用該算法時,httpd有時可以“擺弄”特定維度的品質(zhì)因數(shù)以獲得更好的結(jié)果。httpd可以改變質(zhì)量因素的方式在下面更詳細(xì)地解釋。
透明內(nèi)容協(xié)商 - 當(dāng)瀏覽器通過RFC 2295中定義的機(jī)制專門請求時,使用透明內(nèi)容協(xié)商。此協(xié)商方法使瀏覽器完全控制決定“最佳”變體,因此結(jié)果取決于瀏覽器使用的特定算法。作為透明協(xié)商過程的一部分,瀏覽器可以要求httpd運(yùn)行RFC 2296中定義的“遠(yuǎn)程變量選擇算法”。
httpd協(xié)商算法httpd可以使用以下算法選擇“最佳”變體(如果有)返回瀏覽器。該算法不是可配置的。它的運(yùn)作方式如下:
第1步 - 首先,對于協(xié)商的每個維度,檢查相應(yīng)的Accept *標(biāo)頭字段并為每個變體分配質(zhì)量。如果任何維度的Accept *標(biāo)頭暗示此變體不可接受,則將其刪除。如果沒有變體,請轉(zhuǎn)到第4步。第2步 - 通過消除過程選擇“最佳”變體。按順序應(yīng)用以下每個測試。在每次測試中未選擇的任何變體都被消除。每次測試后,如果只剩下一個變量,請將其選為最佳匹配,然后繼續(xù)執(zhí)行第3步。如果仍有多個變量,請繼續(xù)進(jìn)行下一個測試。
將Accept標(biāo)頭中的質(zhì)量因子與此變體媒體類型的源質(zhì)量因子相乘,并選擇具有最高值的變體。選擇具有最高語言質(zhì)量因子的變體。使用Accept-Language標(biāo)頭中的語言順序(如果存在)或LanguagePriority指令中的語言順序(如果存在),選擇具有最佳語言匹配的變體。選擇具有最高“級別”媒體參數(shù)的變體(用于提供text/html媒體類型的版本)。選擇具有最佳字符集媒體參數(shù)的變體,如Accept-Charset標(biāo)題行所示。除非明確排除,否則使用Charset ISO-8859-1。假定具有text/*媒體類型但未與特定字符集明確關(guān)聯(lián)的變體在ISO-8859-1中。選擇那些具有非ISO-8859-1關(guān)聯(lián)字符集媒體參數(shù)的變體。如果沒有此類變體,請選擇所有變體。選擇具有最佳編碼的變體。如果存在具有用戶代理可接受的編碼的變體,請僅選擇這些變體。否則,如果存在編碼和非編碼變體的混合,請僅選擇未編碼的變體。如果編碼所有變體或未編碼所有變體,請選擇所有變體。選擇內(nèi)容長度最小的變體。選擇剩余的第一個變體。這將是類型映射文件中列出的第一個,或者從目錄中讀取變體時,使用ASCII代碼順序排序時文件名首先出現(xiàn)的變量。該算法現(xiàn)在選擇了一個“最佳”變體,因此將其作為響應(yīng)返回。HTTP響應(yīng)頭Vary設(shè)置為指示協(xié)商的維度(瀏覽器和緩存可以在緩存資源時使用此信息)。到達(dá)此處意味著未選擇任何變體(因?yàn)闉g覽器不接受任何變體)。返回406狀態(tài)(表示“無法接受的表示”),其響應(yīng)正文由列出可用變體的HTML文檔組成。還要設(shè)置HTTP Vary標(biāo)頭以指示方差的維度。
擺弄質(zhì)量值httpd有時會改變上面對httpd協(xié)商算法的嚴(yán)格解釋所期望的質(zhì)量值。這是為了從不發(fā)送完整或準(zhǔn)確信息的瀏覽器的算法中獲得更好的結(jié)果。一些最流行的瀏覽器發(fā)送Accept頭信息,否則會導(dǎo)致在許多情況下選擇錯誤的變體。如果瀏覽器發(fā)送完整且正確的信息,則不會應(yīng)用這些小提琴。
媒體類型和通配符Accept:request標(biāo)頭指示媒體類型的首選項(xiàng)。它還可以包括“通配符”媒體類型,例如image/*或*/*,其中*匹配任何字符串。所以請求包括:
Accept: image/*, */*
Shell
表示任何以image/開頭的類型都是可以接受的,就像任何其他類型一樣。除了可以處理的顯式類型之外,一些瀏覽器還會定期發(fā)送通配符。例如:
Accept: text/html, text/plain, image/gif, image/jpeg, */*
Shell
這樣做的目的是表明明確列出哪些類型是首選的,但如果有不同的表示,那也沒關(guān)系。使用顯式質(zhì)量值,瀏覽器真正想要的是:
Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01
Shell
顯式類型沒有品質(zhì)因子,因此它們默認(rèn)為1.0(最高)的偏好。通配符*/*的優(yōu)先級為0.01,因此只有在沒有變量與明確列出的類型匹配時才會返回其他類型。
如果Accept:標(biāo)頭根本不包含q因子,httpd將*/*”的q值設(shè)置為0.01以模擬所需的行為。它還將格式為type/*的通配符的q值設(shè)置為0.02(因此這些優(yōu)先于匹配*/*的匹配。如果Accept:標(biāo)頭上的任何媒體類型包含aq因子,則這些特殊值不是應(yīng)用,所以來自瀏覽器的請求發(fā)送顯式信息以按預(yù)期開始工作。
語言協(xié)商異常
在httpd 2.0中新增了一些異常,在協(xié)商算法中添加了一些異常,以便在語言協(xié)商找不到匹配時允許優(yōu)雅的回退。
當(dāng)客戶端請求服務(wù)器上的頁面,但服務(wù)器找不到與瀏覽器發(fā)送的Accept語言匹配的單個頁面時,服務(wù)器將向客戶端返回“No Acceptable Variant”或“Multiple Choices”響應(yīng)。為了避免這些錯誤消息,可以將httpd配置為在這些情況下忽略Accept語言,并提供一個未明確匹配客戶端請求的文檔。ForceLanguagePriority指令可用于覆蓋這些錯誤消息中的一個或兩個,并以LanguagePriority指令的形式替換服務(wù)器判斷。
當(dāng)沒有找到其他匹配時,服務(wù)器還將嘗試匹配語言子集。例如,如果客戶端請求英語為en-GB語言的文檔,則HTTP/1.1標(biāo)準(zhǔn)通常不允許服務(wù)器將其與標(biāo)記為en的文檔進(jìn)行匹配。(請注意,在Accept-Language標(biāo)題中包含en-GB肯定是一個配置錯誤,因?yàn)樽x者不太可能理解英國英語,但一般不懂英語。不幸的是,很多當(dāng)前客戶端具有與此類似的默認(rèn)配置。)但是,如果沒有其他語言匹配且服務(wù)器即將返回“No Acceptable Variants”錯誤或回退到LanguagePriority,則服務(wù)器將忽略子集規(guī)范并匹配en-GB相應(yīng)文件。隱式地,httpd會將父語言添加到客戶端可接受的語言列表中,并且質(zhì)量非常低。但請注意,如果客戶端請求en-GB; q=0.9,fr; q=0.8,并且服務(wù)器具有指定為“en”和“fr”的文檔,則將返回“fr”文檔。這對于保持對HTTP/1.1規(guī)范的遵從性以及與正確配置的客戶端有效地工作是必要的。
為了支持高級技術(shù)(例如cookie或特殊URL路徑)來確定用戶的首選語言,因?yàn)閔ttpd 2.0.47 mod_negotiation識別環(huán)境變量prefer-language。如果它存在且包含適當(dāng)?shù)恼Z言標(biāo)記,則mod_negotiation將嘗試選擇匹配的變體。如果沒有這樣的變體,則適用正常的協(xié)商過程。
示例 -
SetEnvIf Cookie "language=(.+)" prefer-language=$1
Header append Vary cookie
Shell
透明內(nèi)容協(xié)商的擴(kuò)展httpd擴(kuò)展了透明內(nèi)容協(xié)商協(xié)議(RFC 2295),如下所示。在變體列表中使用新的{encoding...}元素來標(biāo)記僅具有特定內(nèi)容編碼的變體。RVSA/1.0算法(RFC 2296)的實(shí)現(xiàn)被擴(kuò)展為識別列表中的編碼變體,并且根據(jù)Accept-Encoding請求頭,只要它們的編碼是可接受的,就將它們用作候選變體。在選擇最佳變體之前,RVSA/1.0實(shí)現(xiàn)不會將計算的質(zhì)量因子舍入到5位小數(shù)。
關(guān)于超鏈接和命名約定的注釋如果您正在使用語言協(xié)商,則可以在不同的命名約定之間進(jìn)行選擇,因?yàn)槲募梢跃哂卸鄠€擴(kuò)展名,并且擴(kuò)展的順序通常無關(guān)緊要。
當(dāng)具有該文件的不同語言變體時,典型文件具有MIME類型擴(kuò)展(例如,html),可能是編碼擴(kuò)展(例如,gz),當(dāng)然還有語言擴(kuò)展(例如,en)。
例子:
foo.en.html
foo.html.en
foo.en.html.gz
Shell
這里有一些文件名的例子以及有效和無效的超鏈接:
文件名
有效的超鏈接
無效的超鏈接
foo.html.en
foo,foo.html
—
foo.en.html
foo
foo.html
foo.html.en.gz
foo,foo.html
foo.gz,foo.html.gz
foo.en.html.gz
foo
foo.html,foo.html.gz,foo.gz
foo.gz.html.en
foo,foo.gz,foo.gz.html
foo.html
foo.html.gz.en
foo,foo.html,foo.html.gz
foo.gz
查看上表,應(yīng)該注意到在超鏈接(例如,foo)中始終可以使用沒有任何擴(kuò)展名的名稱。優(yōu)點(diǎn)是可以隱藏文檔rsp的實(shí)際類型。文件并可以在以后更改它,例如,從html更改為shtml或cgi而不更改任何超鏈接引用。
如果您想繼續(xù)在超鏈接中使用MIME類型(例如foo.html),則語言擴(kuò)展(包括編碼擴(kuò)展,如果有的話)必須位于MIME類型擴(kuò)展的右側(cè)(例如,foo.html.en)。
關(guān)于緩存的注意事項(xiàng)當(dāng)緩存存儲表示時,它將其與請求URL相關(guān)聯(lián)。下次請求該URL時,緩存可以使用存儲的表示。但是,如果資源在服務(wù)器上可協(xié)商,則可能導(dǎo)致僅緩存第一個請求的變體,并且后續(xù)緩存命中可能返回錯誤的響應(yīng)。為了防止這種情況,httpd通常將內(nèi)容協(xié)商后返回的所有響應(yīng)標(biāo)記為HTTP/1.0客戶端不可緩存。httpd還支持HTTP/1.1協(xié)議功能,以允許緩存協(xié)商的響應(yīng)。
對于來自HTTP/1.0兼容客戶端(瀏覽器或緩存)的請求,可以使用指令CacheNegotiatedDocs來緩存需要協(xié)商的響應(yīng)。該指令可以在服務(wù)器配置或虛擬主機(jī)中給出,并且不帶參數(shù)。它對來自HTTP/1.1客戶端的請求沒有影響。
對于HTTP/1.1客戶端,httpd發(fā)送Vary HTTP響應(yīng)頭以指示響應(yīng)的協(xié)商維度。緩存可以使用此信息來確定是否可以從本地副本提供后續(xù)請求。要鼓勵緩存使用本地副本而不管協(xié)商維度,請設(shè)置force-no-vary環(huán)境變量。
更多建議: