搜尋

隨機推薦

02 十二月 2009

超文本傳輸協議-HTTP/1.1

http://cl.ly/PF0P/https.jpg

說明

   本文檔規定了互聯網社區的標準組協議,並需要討論和建議以便更加完善。請參考

「互聯網官方協議標準」(STD 1)來瞭解本協議的標準化狀態。本協議不限流傳發佈。

版權聲明

   Copyright (C) The Internet Society (1999).   All Rights Reserved.

摘要

超文本傳輸協議(HTTP)是一種為分佈式,協作式的,超媒體信息系統。它是一種通用的,無狀態(stateless)的協議,除了應用於超文本傳輸外,它也可以應用於諸如名稱服務器和分佈對象管理系統之類的系統,這可以通過擴展它的請求方法,錯誤代碼和消息頭[47]來實現。HTTP的一個特性就是是數據表現形式是可以定義的和可協商性的,這就允許系統能獨立于于數據傳輸被構建。  

HTTP在1990年WWW全球信息剛剛起步的時候就得到了應用。本說明書詳細闡述了HTTP/1.1 協議,是RFC 2068的修訂版[33]。

廣告

 

1 引論

1.1 目的

超文本傳輸協議(HTTP)是一種為分佈式的,協作的,超媒體信息系統,它是面嚮應用層的協議。在1990年WWW全球信息剛剛起步的時候HTTP就得到了應用。HTTP的第一個版本叫做HTTP/0.9,是一種為互聯網原始數據傳輸服務的簡單協議。由RFC 1945[6]定義的HTTP/1.0進一步完善了這個協議。它允許消息以類MIME消息的格式傳送,它包括傳輸數據的元信息和對請求/響應語義的修飾。但是,HTTP/1.0沒有充分考慮到分層代理,緩存的,以及持久連接和虛擬主機的需求的影響。並且隨著不完善的HTTP/1.0應用程序的激增,這就迫切需要一個新的版本,以便能使兩個通信程序能夠確定彼此的真實能力。

此規範定義的協議叫做「HTTP/1.1」,.這個協議與HTTP/1.0相比,此規範更為嚴格,以確保各個協議的特徵得到可靠實現。

實際的信息系統除了簡單的獲取信息之外,還要求更多的功能,包括查找(search),終端更新(front-end update)和註解(annotation)。HTTP為請求提供可擴充方法集和消息頭集[47]。HTTP是建立在統一資源標識符(URI)[3]的約束上的,作為一個地址(URL)[4]或名稱(URN)[20],以指定被一個方法使用的資源。消息以一種類似於互聯網郵件[9]消息格式來傳輸的,互聯網消息格式定義於多目的互聯網郵件擴展(MIME)[7]裡。

HTTP也是用於用戶代理(user agents)和其它互聯網系統的代理/網關之間通信的通信協議,這些互聯網系統可能由SMTP[16],NNTP[13],FTP[18],Gopher[2]和WAIS[10]協議支持。通過這種方式,HTTP允許不同的應用程序對資源進行基本的超媒體訪問。

1.2 要求

本文的關鍵詞「必須」("MUST"),,「不能」("MUST NOT"),「需要」( "REQUIRED"), 「應該」("SHALL"),「不應該」("SHALL NOT"),「應該」("SHOULD"),「不應該」( "SHOULD NOT"),「建議的」( "RECOMMENDED"),「可能」("MAY"), 和「可選的」( "OPTIONAL")將由RFC 2119[34]解釋。

一個應用程序如果不能滿足協議提供的一個或多個MUST或REQUIRED等級的要求,是不符合要求的。一個應用程序如果滿足所有必須(MUST)或需要的(REQUIRED)等級以及所有應該(SHOULD)等級的要求,則被稱為非條件遵循(unconditionally compliant)的;若滿足所有必須(MUST)等級的要求但不能滿足所有應該(SHOULD)等級的要求則被稱為條件遵循的(conditionally compliant)。

1.3 術語

本說明用到了若干術語,以表示HTTP通信中各參與者和對象扮演的不同角色。

連接(connection)

為通信而在兩個程序間建立的傳輸層虛擬電路。

消息(message)

HTTP通信中的基本單元。它由一個結構化的八比特字節序列組成,與第4章定義的句法相匹配,並通過連接得到傳送。

請求(request)

一種HTTP請求消息,參看第5章的定義。

響應(response)

一種HTTP響應消息,參看第6章的定義。

資源(resource)

一種網絡數據對象或服務,可以用第3.2節定義的URI指定。資源可以以多種表現方式(例如多種語言,數據格式,大小和分辨率)或者根據其它方面而而不同的表現形式。

實體(entity)

實體是請求或響應的有效承載信息。一個實體包含元信息和內容,元信息以實體頭域(entity-header field)形式表示,內容以消息主體(entity-body)形式表示。在第7章詳述。

表現形式 (representation)

一個響應包含的實體是由內容協商(content negotiation)決定的。如第12章所述。有可能存在一個特定的響應狀態碼對應多個表現形式。

內容協商(content negotiation)

當服務一個請求時選擇資源的一種適當的表示形式的機制(mechanism),如第12節所述。任何響應裡實體的表現形式都是可協商的(包括錯誤響應)。

變量(variant)

在某個時刻,一個資源對應的表現形式(representation)可以有一個或多個(譯註:一個URI請求一個資源,但返回的是此資源對應的表現形式,這根據內容協商決定)。每個表現形式(representation)被稱作一個變量。 『變量』這個術語的使用並不意味著資源(resource)是由內容協商決定的.。

客戶端(client)

為發送請求建立連接的程序.。

用戶代理(user agent)

初始化請求的客戶端程序。常見的如瀏覽器,編輯器,蜘蛛(可網絡穿越的機器人),或其他的終端用戶工具.

服務器(Server)

服務器是這樣一個應用程序,它同意請求端的連接,並發送響應(response)。任何給定的程序都有可能既做客戶端又做服務器;我們使用這些術語是為了說明特定連接中應用程序所擔當的角色,而不是指通常意義上應用程序的能力。同樣,任何服務器都可以基於每個請求的性質扮演源服務器,代理,網關,或者隧道等角色之一。

源服務器(Origin server)

存在資源或者資源在其上被創建的服務器(server)被成為源服務器(origin server)。  

代理( Proxy)

代理是一個中間程序,它既可以擔當客戶端的角色也可以擔當服務器的角色。代理代表客戶端向服務器發送請求。客戶端的請求經過代理,會在代理內部得到服務或者經過一定的轉換轉至其他服務器。一個代理必須能同時實現本規範中對客戶端和服務器所作的要求。透明代理(transparent proxy)需要代理認證和代理識別,而不修改請求或響應。非透明代理(non-transparent  proxy)需修改請求或響應,以便為用戶代理(user agent)提供附加服務,附加服務包括組註釋服務,媒體類型轉換,協議簡化,或者匿名過濾等。除非透明行為或非透明行為經被顯式地聲明,否則,HTTP代理既是透明代理也是非透明代理。

網關(gateway)

網關其實是一個服務器,扮演著代表其它服務器為客戶端提供服務的中間者。與代理(proxy)不同,網關接收請求,彷彿它就是請求資源的源服務器。請求的客戶端可能覺察不到它正在同網關通信。

隧道(tunnel)

隧道也是一個中間程序,它一個在兩個連接之間充當盲目中繼(blind relay)的中間程序。一旦隧道處於活動狀態,它不能被認為是這次HTTP通信的參與者,雖然HTTP請求可能已經把它初始化了。當兩端的中繼連接都關閉的時候,隧道不再存在。

緩存(cache)

緩存是程序響應消息的本地存儲。緩存是一個子系統,控制消息的存儲、獲取和刪除。緩存裡存放可緩存的響應(cacheable response)為的是減少對將來同樣請求的響應時間和網絡帶寬消耗。任一客戶端或服務器都可能含有緩存,但緩存不能存在於一個充當隧道(tunnel)的服務器裡。

可緩存的(cacheable)

我們說響應(response)是可緩存的,如果這個響應可以被緩存(cache)保存其副本,為的是能響應後續請求。確定HTTP響應的緩存能力(cacheability)在13節中有介紹。即使一個資源(resourse)是可緩存的,也可能存在緩存是否能利用此緩存副本為某個特定請求的約束。 

第一手的(first-hand)

如果一個響應直接從源服務器或經過若干代理(proxy),並且沒有不必要的延時,最後到達客戶端,那麼這個響應就是第一手的(first-hand)。

如果響應通過源服務器(origin server)驗證是有效性(validity)的,那麼這個響應也同樣是第一手的。

顯式過期時間(explicit expiration time)     

是源服務器認為實體(entity)在沒有被進一步驗證(validation)的情況下,緩存(cache)不應該利用其去響應後續請求的時間(譯註:也就是說,當響應的顯式過期時間達到後,緩存必須要對其緩存的副本進行重驗證,否則就不能去利用此副本去響應後續請求)。

啟發式過期時間(heuristic expiration time)      

當沒有顯式過期時間(explicit expiration time)可利用時,由緩存指定過期時間.

年齡(age)

一個響應的年齡是從被源服務器發送或被源服務器成功驗證到現在的時間。

保鮮壽命(freshness lifetime)

一個響應產生到過期之間的時間。

保鮮(Fresh)    

如果一個響應的年齡還沒有超過保鮮壽命(freshness lifetime),那麼它就是保鮮的.。

陳舊(Stale)

一個響應的年齡已經超過了它的保鮮壽命(freshness lifetime),那麼就是陳舊的.

語義透明(semantically transparent)

緩存(cache)可能會以一種語意透明(semantically transparent)的方式工作。這時,對於一個特定的響應,使用緩存既不會對請求客戶端產生影響也不會對源服務器產生影響,緩存的使用只是為了提高性能。當緩存(cache)具有語意透明時,客戶端從緩存接收的響應跟直接從源服務器接收的響應完全一致(除了使用hop-by-hop頭域)。

驗證器(Validator)

驗證器其實是協議元素(例如:實體標籤(entity tag)或最後修改時間(last-modified time)等),這些協議元素被用於識別緩存裡保存的副本(即緩存項)是否等價於源服務器的實體的副本。

上游/下游(upstream/downstream)

上游和下游描述了消息的流動:所有消息都是從上游流到下游。

內向/外向(inbound/outbound)

內向和外向指的是消息的請求和響應路徑:「內向」即「移向源服務器」,「外向」即「移向用戶代理(user agent)」。

1.4 總體操作

HTTP協議是一種請求/響應型的協議。 客戶端給服務器發送請求的格式是一個請求方法(request method),URI,協議版本號,然後緊接著一個包含請求修飾符(modifiers),客戶端信息,和可能的消息主體的類MIME(MIME-like)消息。服務器對請求端發送響應的格式是以一個狀態行(status line),其後跟隨一個包含服務器信息、實體元信息和可能的實體主體內容的類MIME(MIME-like)的消息。其中狀態行(status line)包含消息的協議版本號和一個成功或錯誤碼。HTTP和MIME之間的關係如附錄19.4節所闡述。

大部分的HTTP通信是由用戶代理(user agent)發起的,由應用於一個源服務器資源的請求構成。最簡單的情形,這可以通過用戶代理(UA)和源服務器(O)之間的單一連接(v)來實現。

請求鏈(Request chain)-------------------------------------- ----------à

用戶代理(UA)----------------單一連接(v)--------------源服務器(O)

<----------------------------------------------------------響應鏈(response chain)

有可能在請求/響應鏈中出現一個或多個中間者(intermediares),這是比較複雜的情形。常見的中間者(intermediares)有三種:代理(proxy),網關(gateway)和隧道(tunnel)。代理(proxy)是一種轉發代理(a  forwarding  agent),它接收絕對URI(absoulute url,相對於相對url)請求,重寫全部或部分消息,然後把格式化後的請求發送到URI指定的服務器上。網關是一種接收代理(receiving agent),它充當一個在服務器之上的層(layer),必要時它會把請求翻譯成為下層服務器的協議。隧道不改變消息而充當兩個連接之間的中繼點;它用於通信需要穿過中間者(如防火牆)甚至當中間者不能理解消息內容的時候。

請求鏈(request chain)----------------------------------------à

UA-----v-----A-----v-----B-----v-----C------------v-----------------O

 <----------------------------------------響應鏈(response chain)

上圖顯示了用戶代理(user agent)和源服務器之間的三個中間者(A,B和C)。整條鏈的請求或響應將會通過四個被隔離開的連接。這個不同點很重要,因為某些HTTP通信選項有可能只能採用最近的非隧道鄰接點的連接,有可能只採用鏈的端點(end-point),或者也有可能只採用於鏈上所有連接。圖表儘管是線性的,每個參與者可能忙於多個並發的通信。例如,B可以接收來自不是A的許多客戶端的請求,並且/或者可以把請求轉發到不是C的服務器,與此同時C正在處理A的請求。

通信中任何非隧道成員都可能會採用一個內部緩存(internal cache)來處理請求。如果沿著鏈的成員有請求已緩存的響應,請求/響應鏈就會大大縮短。下圖闡明了一個最終請求響應鏈,假定B擁有一個來自於O(通過C)的以前請求響應的緩存副本,並且此請求的響應並未被UA或A緩存。

請求鏈(request chain)---------->

UA-----v----------A-----v-----B-----C----O

<---------響應鏈 (response chain)

並不是所有的響應都能有效地緩存,一些請求可能含有修飾符(modifiers),這些修飾符對緩存動作有特殊的要求。HTTP對緩存行為(behavior)和可緩存響應(cacheable responses)的定義在第13章定義。

實際上,目前萬維網上有多種被實踐和部署的緩存和代理的體系結構和配置。這些系統包括節省帶寬的緩存代理(proxy cache)層次(hierarchies)系統,可以廣播(broadcast)或多播(multicast)緩存數據的系統,通過CD-ROM發佈緩存數據子集的機構,等等。HTTP系統(http system)會被應用於寬帶連接的企業局域網中的協作,並且可以被用於PDAs進行低耗無線斷續連接訪問。HTTP1.1的宗旨是為了支持各種各樣的已經部署的配置,同時引進一種協議結構,讓它滿足可以建立高可靠性的web應用程序,即使不能達到這種要求,也至少可以可靠的定位故障。

HTTP通信通常發生在TCP/IP連接上。默認端口是TCP 80,不過其它端口也可以使用。但並不排除HTTP協議會在其它協議之上被實現。HTTP僅僅期望的是一個可靠的傳輸(譯註:HTTP一般建立在傳輸層協議之上);所以任何提供這種保證的協議都可以被使用;協議傳輸數據單元(transport data unit)與HTTP/1.1請求和響應的消息結構之間的映像已經超出了本規範的範圍。

大部分HTTP/1.0的實現都是對每個請求/響應交換(exchange)產生一個新的連接。而HTTP/1.1中,一個連接可以用於一個或更多請求/響應交換,雖然連接可能會因為各種原因中斷(見第8.1節)。

2 符號習慣和一般語法

2.1 擴充的BNF(擴充的 巴科斯-諾爾範式)

本文檔規定的所有機制都用兩種方法描述:散文體(prose)和類似於RFC 822的擴充Backus-Naur Form(BNF)。要理解本規範,使用者需熟悉符號表示法。擴充BNF結構如下:

名字(name)=定義(definition)

名字(name)就是代表規則的名字,規則名裡不能包含「<」和「>」,通過等號把規則名和規則定義(definiation)分離開。空格只有在採用延續行縮進來指定跨度多於一行的規則定義的時候才有意義。某些基本規則(basic rules)使用大寫字母包含在規則定義裡, 如SP,LWS,HT,CRLF,DIGIT,ALPHA,等等。尖括號可以包含在規則定義裡,只要它們的存在有利於區分規則名的使用。

「字面文本」(「literal」)

字面文本(literal text)兩邊用引號。除非聲明,字面文本大小寫不敏感(譯註:如,HEX = "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT 裡的A,B,C,D等等都是字面文本(literal text))。

規則1 | 規則2

由豎線(「|」)分開的元素是可選的,例如,「yes | no」表示yes或no都是可接受的。

(規則1 規則2)

圍在括號裡的多個元素視作一個元素。所以,「(elem (foo | bar) elem)」符合的字符串是「elem foo elem」和「elem bar elem」。

*規則

前面的字符「*」表示重複。完整的形式是「<n>*<m>元素」,表示元素至少出現<n>次,至多出現<m>次。默認值是0和無窮大,所以"*(元素)"允許任何數值,包括零;"1*元素"至少出現一次;"1*2element"允許出現一次或兩次。

[規則]

方括號裡是任選元素;「[foo bar]」相當於「*1(foo bar)」。

N 規則

特殊的重複:「<n>(元素)」與「<n>*<n>(元素)」等價;就是說,(元素)正好出現<n>次。這樣2DIGIT是一個兩位數字,3ALPHA是一個由三個字符組成的字符串。

#規則

類似於「*」,結構「#」是用來定義一系列元素的。完整的形式是<n>#<m>元素,表示至少<n>個元素,至多<m>個元素,元素之間被一個或多個逗號(「,」)以及可選的線性空白(LWS)隔開了。這就使得表示列表這樣的形式變得非常容易;像

(*LWS element *(*LWS ","*LWS element))

就可以表示為

1#element  

無論在哪裡使用這個結構,空元素都是允許的,但是不計入元素出現的次數。換句話說 ,

「(element ), , (element)  」是允許的,但是僅僅視為兩個元素。因此,在至少需要一個元素的地方,必須存在至少一個非空元素。默認值是0和無窮大,這樣,「#element」允許任意零個或多個元素;「1# element」需要至少一個;「1#2element」允許一個或兩個元素。

註釋(comment)

用分號引導註釋。

隱含的*LWS

本規範所描述的語法是基於字(word-based)的。除非特別註明,線性空白(LWS)可以出現在任何兩個相鄰字之間(標記(token)或引用字符串(quoted-string)),以及相鄰字和間隔符之間,但是這並沒有改變對一個域的解釋。任何兩個標記(token)之間必須有至少一個分割符,否則將會被理解為只是一個標記。

 

2.2基本規則 (basic rule)

下面的規則貫穿於本規範的全文,此規則描述了基本的解析結構。US-ASCII(美國信息交換標準碼)編碼字符集是由ANSI X3.4-1986[21]定義的。 

       OCTET(字節)    = <任意八比特的數據序列>

       CHAR           = <任意ASCII字符(ascii碼值從 0到127的字節)>

       UPALPHA        = <任意大寫字母"A"..."Z">

       LOALPHA        = <任意小寫字母"a"..."z">

       ALPHA          = UPALPHA | LOALPHA 

       DIGIT          = <任意數字0,1,...9>

       CTL          = <任意控制字符(ascii碼值從0 到 31的字節)及刪除鍵DEL(127>

       CR             = <US-ASCII CR, 回車(13)>

       LF             = <US-ASCII LF, 換行符(10)>

       SP             = <US-ASCII SP, 空格(32)>

       HT             = <US-ASCII HT, 水平製表 (9)>

       <">            = <US-ASCII雙引號(34)>

HTTP/1.1將 CR LF 的序列定義為任何協議元素的行尾標誌,但這個規定對實體主體(endtity-body)除外(要求比較鬆的應用見附錄19.3)。實體主體(entity-body)的行尾標誌是由其相應的媒體類型定義的,如3.7節所述。

       CRLF           = CR LF

HTTP/1.1 的消息頭域值可以摺疊成多行,但緊接著的被摺疊行由空格(SP)或水平製表(HT)摺疊標記開始。所有的線性空白(LWS)包括被摺疊行的摺疊標記(空格SP或水平製表鍵HT),具有同SP一樣的語義。接收者在解析域值並且將消息轉送到下游(downstream)之前可能會將任何線性空白(LWS)替換成單個SP(空格)。

       LWS            = [CRLF] 1*(SP | HT)

下面的TEXT規則僅僅適用於頭域內容和值的描述,不會被消息解釋器解析。TEXT裡的字可以包含不僅僅是ISO-8859-1[22]裡的字符集,也可以包含RFC 2047裡規定的字符集。

       TEXT           = <除CTLs以外的任意OCTET,但包括LWS>

一個CRLF只有作為HTTP消息頭域延續的一部分時才在TEXT定義裡使用。

十六進制數字字符用在多個協議元素(protocol element)裡。

       HEX            = "A" | "B" | "C" | "D" | "E" | "F"

                      | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT

許多HTTP/1.1的消息頭域值是由LWS或特殊字符分隔的字構成的。這些特殊字符必須先被包含在引用字符串(quoted string)裡之後才能用於參數值(如3.6節定義)裡。

       token (標記)        = 1*<除CTLs與分割符以外的任意CHAR >

       separators(分割符)    = "(" | ")" | "<" | ">" | "@"

                               | "," | ";" | ":" | """ | <">

                                      | "/" | "[" | "]" | "?" | "="

                                      | "{" | "}" | SP | HT

通過用圓括號括起來,註釋(comment)可以包含在一些HTTP頭域裡。註釋只能被包含在域值定義裡有「comment」的域裡。在其他域裡,圓括號被視作域值的一部分。

       comment (註釋)= "(" *(ctext | quoted-pair | comment )」 )"

       ctext          = <除"(" 和 ")"以外的任意TEXT >

如果一個TEXT若被包含在雙引號裡,則當作一個字。

quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )

qdtext       = <any TEXT except <">>

斜劃線(""")可以被作為單字符的引用機制,但是必須要在quoted-string和comment構造之內。

quoted-pair = """ CHAR

3 協議參數

3.1 HTTP版本

HTTP使用一個「<major>.<minor>」數字模式來指明協議的版本號。為了進一步的理解HTTP通信,協議的版本號指示了發送端指明消息的格式和能力,而不僅僅是通過雙方通信而獲得的通信特性。當消息元素的增加不會影響通信行為或擴展了域值時,協議版本是不需要修改的。當協議會因為添加一些特徵而做了修改時,<minor>數字就會遞增。這些修改不會影響通常的消息解析算法,但它會給消息添加額外的語意(semantic)並且會暗示發送者具有額外的能力。協議的消息格式發生變化時,<major>數字就會增加。

HTTP消息的版本在HTTP-Version域被指明,HTTP-Version域在消息的第一行中。

HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT

注意major和minor數字必須被看成兩個獨立整數,每個整數都可以遞增,並且可以增大到大於一位數的整數,如HTTP/2.4比HTTP/2.13低,而HTTP/2.4又比HTTP/12.3低。前導0必須被接收者忽略並且不能被發送者發送。

一個應用程序如果發送或響應消息裡的包含HTTP-Version為「HTTP/1.1」的消息,那麼此應用程序必須至少條件遵循此協議規範。最少條件遵循此規範的應用程序應該把「HTTP/1.1」包含在他們的消息的HTTP-Version裡,並且對任何不兼容HTTP/1.0的消息也必須這麼做。關於何時發送特定的HTTP-Version值的細節,參見RFC2145[36]。

應用程序的HTTP版本是應用程序最少條件遵循的最高HTTP版本。

當代理或網關應用程序轉發(forwarding)消息的協議版本不同於代理或網關應用程序本身協議版本的時候,代理(proxy)和網關(gateway)應用程序就要小心。因為消息裡協議版本說明了發送者處理協議的能力,所以一個代理/網關千萬不要發送一個高於該代理/網關應用程序協議版本的消息。如果代理或網關接收了一個更高版本的消息,它必須要麼使協議的版本降低,要麼以一個錯誤響應,或者要麼切換到隧道行為(tunnel behavior)。

自從RFC 2068[33]發佈後,由於存在與HTTP/1.0代理(proxy)的互操作問題,所以緩存代理(caching proxies)必須能提升請求的版本到他們能支持的程度,但網關(gateway)可以這麼做也可以不這麼做,而隧道(tunnels)卻不能這麼做。代理(Proxy)/網關(gateway)的響應(Response)必須和請求(request)的主版本(major version)號保持一致。

注意:HTTP版本間的轉換可能會對消息頭域(header fields)在版本裡有或沒有而進行改變。

3.2 通用資源標識符(URI)

URIs有許多名字已為人所知:WWW地址,通用文檔標識符,通用資源標識符[3],以及後來的統一資源定位器(URL)[4]和統一資源名稱(URN)[20]。就HTTP而言,通用資源標識符(URI)只是簡單的格式化字符串---通過名稱,位置,或其它特徵---識別一個資源。

3.2.1一般語法

根據使用的背景,HTTP裡的URIs可以表示成絕對(absoulute)形式或相對形式(相對URI基於根URI[11])。兩種形式的區別是根據這樣的事實:絕對URI總是以一個模式(scheme)名作為開頭,其後是一個冒號。關於URL更詳盡的語法和含義請參看「統一資源標識符(URI):一般語法和語義」,RFC 2396 [42](代替了RFCs 1738 [4]和RFC 1808 [11])。本規範採用了RFC 2396裡的」URI-reference」,"absoluteURI","relativeURI","port","host","abs_path","rel_path",和"authority"的定義格式。

HTTP協議不對URI的長度作事先的限制,服務器必須能夠處理任何他們提供資源的URI,並且應該能夠處理無限長度的URIs,這種無效長度的URL可能會在客戶端以基於GET方式的請求時產生。如果服務器不能處理太長的URI的時候,服務器應該返回414狀態碼(此狀態碼代表Request-URI太長)。

注:服務器在依賴大於255字節的URI時應謹慎,因為一些舊的客戶或代理實現可能不支持這些長度。

3.2.2 HTTP URL

在HTTP協議裡,http模式(http scheme)被用於定位網絡資源(resourse)的位置。本節定義了http URLs這種特定模式(scheme)的語法和語義。

   http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]

如果端口為空或未給出,就假定為80。它的語義即:已識別的資源存放於正在監聽tcp連接的那個端口的服務器上,並且請求資源的的Request-UR為絕對路徑(5.1.2節)。無論什麼可能的時候,URL裡使用IP地址都是應該避免的(參看RFC 1900 [24])。如果絕對地址(abs_path)沒有出現在URL裡,那麼應該給出"/"。如果代理(proxy)收到一個主機(host)名,但是這個主機名不是全稱域名(fully quanlified domain name),則代理應該把它的域名加到主機名上。如果代理(proxy)接收了一個全稱域名,代理不能改變主機(host)名稱。

3.2.3 URI 比較

當比較兩個URI是否匹配時,客戶應該對整個URI比較時應該區分大小寫,並且一個字節一個字節的比較。 但下面有些特殊情況:

- 一個為空或未給定的端口等同於URI-refernece(見RFC 2396)裡的默認端口;

- 主機(host)名的比較必須不區分大小寫;

- 模式(scheme)名的比較必須是不區分大小寫的;

- 一個空絕對路徑(abs_path)等同於"/"。

除了「保留(reserved)」和「不安全(unsafe)」字符集裡的字符(參見RFC 2396 [42]) ,其它字符和它們的"%HEXHEX"編碼的效果一樣。 

例如,以下三個URI是等同的:

      http://abc.com:80/~smith/home.html

      http://ABC.com/%7Esmith/home.html

      http://ABC.com:/%7esmith/home.html

3.3 日期/時間格式(Date/Time Formats)

3.3.1完整日期 (Full Date)

 HTTP應用曾經一直允許三種不同日期/時間格式:

      Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123

      Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036

      Sun Nov 6 08:49:37 1994       ; ANSI C's asctime() format

第一種格式是作為Internet標準提出來的,它是一個國定長度的,由RFC 1123 [8](RFC 822[9]的升級版本)定義的一個子集。第二種格式使用比較普遍,但是基於廢棄的RFC 850 [12]協議,並且沒有年份。如果HTTP/1.1客戶端和服務器要解析日期,他們必須能接收所有三種格式(為了兼容HTTP/1.0),但是它們只能用RFC 1123裡定義的日期格式來填充頭域(header field)的值裡用到HTTP-date的地方。

注:日期值的接收者被鼓勵能可靠地接收來自於非HTTP應用程序發送的的日期值,例如有時可以通過代理(proxy)/網關(gateway)向SMTP或NNTP獲取或提交消息。

所有的HTTP日期/時間都必須以格林威治時間(GMT)表示。對HTTP而言,GMT完全等同於UTC(世界協調時間)。前兩種日期/時間格式裡包含「GMT」,它是時區的三個字面的簡寫,並且當讀到一個asctime格式時必須先被假定是GMT時間。HTTP日期(HTTP-date)區分大小寫,不能在此語法中除SP之外包含一個多餘的LWS。

       HTTP-date    = rfc1123-date | rfc850-date | asctime-date

       rfc1123-date = wkday "," SP date1 SP time SP "GMT"

       rfc850-date = weekday "," SP date2 SP time SP "GMT"

       asctime-date = wkday SP date3 SP time SP 4DIGIT

       date1        = 2DIGIT SP month SP 4DIGIT

                      ; day month year (e.g., 02 Jun 1982)

       date2        = 2DIGIT "-" month "-" 2DIGIT

                      ; day-month-year (e.g., 02-Jun-82)

       date3        = month SP ( 2DIGIT | ( SP 1DIGIT ))

                      ; month day (e.g., Jun 2)

       time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT

                      ; 00:00:00 - 23:59:59

       wkday        = "Mon" | "Tue" | "Wed"

                    | "Thu" | "Fri" | "Sat" | "Sun"

       weekday      = "Monday" | "Tuesday" | "Wednesday"

                    | "Thursday" | "Friday" | "Saturday" | "Sunday"

       month        = "Jan" | "Feb" | "Mar" | "Apr"

                    | "May" | "Jun" | "Jul" | "Aug"

                    | "Sep" | "Oct" | "Nov" | "Dec"

注意:HTTP對日期/時間格式的要求僅僅應用在協議流的使用。客戶和服務器不必把這種格式應用於用戶呈現(user presentation),請求記錄日誌,等等。.

3.3.2 Delta Seconds(秒間隔)

 一些HTTP頭域(header field)允許時間值以秒為單位,以十進制整數表示,此值代表消息接收後的時間。

   delta-seconds = 1*DIGIT

3.4 字符集 (Character Sets)

 HTTP使用術語「字符集」的定義,這和MIME中所描述的是一樣.

本文檔中的術語「字符集」涉及到一種方法,此方法是用單個或多個表將一個字節序列轉 換成一個字符序列(譯註:從這裡來看,這應該是一種映射關係,表保存了映射關係)。注意在反方向上無條件的轉換是不成立的,因為並不是所有的字符都能在一 個給定的字符集裡得到,一個字符集裡可能提供多個字節序列表徵一個特定的字符。這個定義為的是允許不同種類的字符編碼從單一簡單表映射(如US-ASCII)到複雜表的轉換方法,例如利用ISO-2022技術。然而,相關於MIME字符集名字的定義必須要充分指定從字節到字符的映射。特別是利用外部外圍信息來精確確定映射是不允許的.

註:這裡使用的術語「字符集」一般的被稱作一種「字符編碼」。不過既然HTTP和MIME在同一機構註冊,術語統一是很重要的。

HTTP字符集的標記(token)是用不區分大小寫的。所有的標記由IANA字符集註冊機構[19]定義。

       charset = token

儘管HTTP允許用任意標記(token)作為字符集(charset)值,但這個標記已經在IANA字符集註冊機構註冊過了,那麼這個標記必須代表在該註冊機構定義的字符集。對那些非IANA定義的字符集,應用程序應該限制使用。

HTTP協議的實現者應該注意IETF字符集的要求[38][41].

3.4.1丟失字符集(Missing Charset)

一些HTTP/1.0應用程序當他們解析Content-Type頭時,當發現沒有字符集參數(charset parameter,譯註:Content-Type: text/plain; charset=UTF-8,此時charset=UTF-8就是字符集參數)可用時,這意味著接收者必須猜測實體主體(entity body)的字符集到底是什麼。如果發送者希望避免這種情況,他應該在Content-Type頭域裡包含一個字符集參數,即使字符集是ISO-8859-1的也應該指明,這樣就不會讓接收者產生混淆。

不幸的是,一些舊的HTTP/1.0客戶端不能處理在Content-Type頭域裡明確指定的字符集參數。HTTP/1.1接收端必須要認真對待發送者提供的字符集;並且當用戶代理(user agent,譯註:如瀏覽器)開始呈現一個文檔時,雖然用戶代理可以猜測文檔的字符集,但如果content-type頭域裡提供了字符集,並且用戶代理也支持這種字符集的顯示,不管用戶代理是否願意,它必須要利用這種字符集。參見3.7.1節。

3.5 內容編碼(Content Codings)

內容編碼(content coding)的值表示一種曾經或能被應用於一個實體的編碼轉換(encoding   transformation)。內容編碼主要用於文檔的壓縮或其它有效的變換,但這種變換必須不能丟失文檔的媒體類型的特性,並且不能丟失文檔的信息(譯註:就像有損壓縮和無損壓縮,前者不會丟失信息,後者會丟失信息)。實體經常被編碼後保存,然後傳送出去,並且在接收端被解碼。

       content-coding   = token

所有內容編碼(content-coding)的值是不區分大小寫的。HTTP/1.1在接受譯碼 (Accept-Encoding,14.3節)和內容譯碼(Content-Encoding)(14.11節)頭域裡使用內容編碼(content-coding)的值。儘管該值描述了內容編碼,更重要的是它指出了一種解碼機制,利用這種機制對實體的編碼進行解碼。

網絡分配數字權威( (IANA)充當內容編碼的值標記(token)註冊機構。最初,註冊表裡包含下列標記:

gzip(壓縮程序) 

一種由文件壓縮程序"gzip"(GNU zip)產生的編碼格式(在RFC 1952中描述)。這種編碼格式是一種具有32位CRC的Lempel-Ziv編碼(LZ77)。

compress(壓縮)

一種由UNIX文件壓縮程序"compress"產生的編碼格式。這種編碼格式是一種具有可適應性的Lempel-Ziv-Welch編碼(LZW)。

對於將來的編碼,用程序名識表徵編碼格式是不可取。在這裡用到他們是因為他們在歷史的作用,雖然這樣做並不好。為了同以前的HTTP實現相兼容,應用程序應該將"x-gzip"和"x-compress"分別等同於"gzip"和"compress"。

deflate(縮小) 

deflate編碼是由RFC 1950 [31]定義的"zlib"編碼格式與RFC 1951 [29]裡描述的"deflate"壓縮機制的組合的產物。

identity(一致性)

Identity是缺省編碼;指明這種編碼表明不進行任何編碼轉換。這種內容編碼僅被用於接受譯碼(Accept-Encoding)頭域裡,但不能被用在內容譯碼(Content-Encoding)頭域裡。.

新的內容編碼的值標記(token)應該被註冊;為了實現客戶和服務器間的互操作性,實現新值的內容編碼算法規範應該能公開利用並且能獨立實現,並且與本節中被定義的內容編碼目的相一致。

3.6 傳輸編碼 (Transfer Codings)

傳輸編碼(transfer-coding ,譯註:transfer coding和和transfer-coding這兩個術語在本協議規範裡所表達的意思其實沒什麼太大區別,「transfer-coding」可能更能表達語意,因為它是規則中的規則名)的值被用來表示一個曾經,能夠,或可能應用於一個實體的編碼轉換,傳輸編碼是為了能夠確保網絡安全傳輸。這不同於內容編碼(content coding),因為傳輸編碼(transfer coding)是消息的屬性而不是實體的屬性。

       transfer-coding = "chunked" | transfer-extension

       transfer-extension      = token *( ";" parameter )

   參數(parameter)採用屬性/值對的形式.

       parameter                 = attribute "=" value

       attribute                   = token

       value                     = token |   quoted-string

所有傳輸編碼的值是大小寫不敏感。傳輸編碼的值在TE頭域(14.39節)和在傳輸譯碼(Transfer-encoding) 頭域中(14.41節)被運用。

無論何時,傳輸編碼(transfer-coding)應用於一個消息主體(message body)時,如果存在多個傳輸編碼,則這些傳輸編碼中必須包括「塊」("chunked")傳輸編碼,除非通過關閉連接而使消息結束。當「塊」(「chunked」)傳輸編碼被用於傳輸編碼時,它必須是應用於消息主體的最後傳輸編碼。"塊"("chunked")傳輸編碼最多只能用於消息主體(message-body)一次。規定了上述規則後,接收者就可以確定消息的傳輸長度(transfer-length)(4.4節)

傳輸編碼與MIME[7]的內容傳輸譯碼(Content-Transfer-Encoding,MIME [7])的值相似,它被定義能夠實現在7位傳輸服務上保證二進制數據的安全傳輸。不過,傳輸編碼與內容傳輸譯碼(Content-Transfer-Encoding)對純8位傳輸協議有不同的側重點。在HTTP中,消息主體存在不安全的特性是因為有時候很難確定消息主體的長度(7.2.2節)和在共享的傳輸上加密數據。

網絡分配數字權威(IANA)擔任註冊傳輸編碼的值標記(token)的角色。起初,註冊包含如下標記:"塊"(3.6.1節),"身份"(3.6.2節),"gzip"(3.5節),"壓縮"(3.5節),和"縮小"(3.5節).

新的傳輸編碼的值標記應該註冊,這同新的內容編碼的值標記也需要註冊一樣。.

如果接收端接收到一個經過傳輸編碼編碼過的實體主體(entity body)但它不能對這個編碼後的實體主體進行解碼,那麼它應返回501(不能實現),並且要關閉連接。服務器不能向HTTP/1.0客戶端發送傳輸編碼.。

3.6.1塊傳輸編碼(Chunked Transfer Coding)

塊編碼(chunked encoding)改變消息主體使消息主體(message body)成塊發送。每一個塊有它自己的大小(size)指示器,在所有的塊之後會緊接著一個可選的包含實體頭域的尾部(trailer)。這種編碼允許發送端能動態生成內容,並能攜帶能讓接收端判斷消息是否接收完整的有用信息。 

       Chunked-Body(塊正文)   = *chunk(塊)

                                 last-chunk(最後塊)

                                    trailer(尾部)

                             CRLF

       chunk(塊)          = chunk-size [ chunk-extension ] CRLF

                               chunk-data CRLF

       chunk-size     = 1*HEX

       last-chunk     = 1*("0") [ chunk-extension ] CRLF      

       chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )             

       chunk-ext-name = token

       chunk-ext-val = token | quoted-string

       chunk-data     = chunk-size(OCTET)

       trailer        = *(entity-header CRLF)

chunk-size是用16 進制數字字符串。塊編碼(chunked encoding)以大小為0的塊結束,緊接著是尾部(trailer),尾部以一個空行終止。

尾部(trailer)允許發送端在消息的末尾包含額外的HTTP頭域(header field)。Trailer頭域(Trailer header field,在14.40節闡述)來指明哪些頭域被包含在塊傳輸編碼的尾部(trailer) (見14.40節)

如果服務器要使用塊傳輸編碼進行響應,除非以下至少一條為真時它才能包含尾部(trailer):

a)如果此響應的對應請求包括一個TE頭域,並且利用 「trailers」指明了塊傳輸編碼響應的尾部是可以接受的(TE頭域在14.39節中描述;或者

 b)如果是源服務器進行響應,響應裡trailer字段裡全部包含的是可選的元信息,並且接收端接收此塊傳輸編碼響應時可能不會理會響應的尾部(以一種源服務器是可以接受的方式)。換句話說,源服務器原意接受尾部(trailer)可能會在到達客戶端時被丟棄的可能性。

當消息被一個HTTP/1.1(或更高版本)的代理(proxy)接收並轉發到一個HTTP/1.0接收端的時候,此要求防止了一種互操作性的失敗。  

在附錄19.4.6節介紹了一個例子,這個例子介紹怎樣對一個塊主體(chunked-body)進行解碼。

所有HTTP/1.1應用程序必須能接收和解碼以塊(chunked)傳輸編碼進行編碼的消息主體,並且必須能忽略它們不能理解的塊擴展(chunk-extentsion)。

3.7 媒體類型(Media Type)

為了提供開放的,可擴展的數據類型和類型協商,HTTP在Content-Type(14.17節)實體頭域和Accept請求頭域裡利用了網絡媒體[17]類型。

media-type    = type "/" subtype *( ";" parameter )

type               = token

subtype         = token

參數(parameter)以一種 屬性/值(attribute/value)形式(如3.6節定義)跟隨 類型/子類型(type/subtype)。

類型(type),子類型(subtype),和參數(parameter)裡屬性名稱是大小寫不敏感的。參數值有可能是大小寫敏感的,也可能不是,這根據參數里屬性名稱的語意。線性空白(LWS)不能被用於類型(type)和子類型(subtype)之間,也不能用於參數的屬性和值之間。參數的出現或不出現對處理媒體類型(media-type)可能會有幫助,這取決於它在媒體類型註冊表裡的定義。

注意一些舊的HTTP應用程序不能識別媒體類型的參數(parameter)。當向一個舊HTTP應用程序發送數據時,發送端只有在被type/subtype定義裡需要時才使用類型參數(parameter)。

媒體類型(media-type)值需要被註冊到網絡數字分配權威(IANA[19])裡。媒體類型的註冊程序在RFC 1590[17]中大概描述。使用未經註冊的媒體類型是不被鼓勵的。

 

3.7.1規範化和文本缺省 (Canonicalization and Text Defaults)

網絡媒體類型以一種規範化格式被註冊。一個實體主體(entity-body)通過HTTP消息傳輸,在傳輸前必須以一種合適的規範化格式來表示,但除了文本類型(text type),文本類型將會在下一段闡述。

當消息以一種規範化格式表現時,文本類型的子類型(subtype)會運用GRLF作為文本裡的換行符。HTTP放鬆了這個要求,允許文本媒體以一個CR或LF代表一個換行符傳輸,並且如果這樣做的話就要貫穿整個實體主體(entity-body)。HTTP應用程序必須能接收CRLF,CR和LF作為在文本媒體一個換行符。另外,如果文本裡所屬的字符集(character set)不能利用字節13和10來分別地表示CR和LF,這是因為存在一些多字節字符集,HTTP允許應用字符集裡等價於CR和LF的字節序列來表示換行符。對換行符的靈活處理只能應用於實體主體裡的文本媒體;在HTTP消息控制結構(如頭域和多邊界體(multipart boundaries))裡,一個純粹的CR或LF都不能代替CRLF的作用。

如果一個實體主體(entity-body)用內容編碼(content-coding)進行編碼,原始數據在被編碼前必須是一種以上定義的媒體類型格式。.

"charset"參數(parameter)被應用於一些媒體類型,來定義數據的字符集(見3.4節)。當發送端沒有指明charset參數(parameter)時,「text」類型的子媒體類型(subtype)被接收端接收後會被認為是缺省的ISO-8859-1字符集。非「ISO-8859-1」字符集和它的子類(subsets)的數據必須被指示恰當的字符集。3.4.1節描述了兼容性問題。

 

3.7.2多部分類型(Multipart type)

MIME提供了一系列「多部分」(multipart)類型---在單個消息主體內包裝一個或多個實體。所有的多部分類型共享一個公共的語法(這在RFC 2046[40]的5.1.1節中描述),並且包含一個邊界(boundary)參數作為多部分媒體類型的值的一部分。多部分類型的消息主體是一個協議元素,並且必須用CRLF來標識體部分(body-part,譯註:見RFC 2046 的5節)之間的換行。

不同於RFC 2046裡的多部分消息類型的描述,HTTP1.1規定任何多部分類型的消息尾聲(epilogue,譯:見RFC 2046對多部分消息類型的規則描述)必須不能存在;HTTP應用程序不能傳輸尾聲(epilogue)(即使原始的多部分消息尾部包含一個尾聲)。存在這些限制是為了保護多部分消息主體的自我定界的特性,因為多部分邊界的結束(譯註:根據RFC2046中定義,多部分邊界結束後可能還會有尾聲)標誌著消息主體的結束。

通常,HTTP把一個多部分類型的消息主體(message-body)和任何其它媒體類型的消息主體等同對待:嚴格看作有用的負載體。有一個例外就是「multipart/byterange」類型(附錄19.2),當它出現在206(部分內容)響應時,此響應會被一些HTTP緩存機制解析,緩存機制將會在13.5.4節和14.16節介紹。在其它情況下,一個HTTP用戶代理會遵循MIME用戶代理一樣或者相似的行為,這依賴於接收何種多部分類型。一個多部分類型消息的每一個體部分(body-part)裡的MIME頭域對於HTTP除了MIME語意並沒有太大意義。

通常, 一個HTTP用戶代理應該遵循與一個MIME用戶代理相同或相似的行為。如果一個應用程序收到一個不能識別的多部分子類型,這個應用程序必須將它視為"multipart/mixed"。

註:"multipart/form-data"類型已經被特別地定義用來處理Post請求方法傳送的窗體數據,這在RFC 1867[15]裡定義。

3.8 產品標記 (product Tokens)

產品標記用於使通信應用軟件能通過軟件名稱和版本來標識自己。很多頭域都會利用產品標記,這些頭域允許構成應用程序重要部分的子產品能以空白分隔去列舉。通常為了識別應用程序,產品以應用程序的重要性的順序來列舉的。

       product               = token ["/" product-version]

       product-version       = token

例:

User-Agent:CERN-LineMode/2.15 libwww/2.17b3

Server: Apache/0.8.4

產品標記應言簡意賅。它們不能用來做廣告或其他不重要的信息。雖然任一標記可能出現product-version裡,但這個標記僅能用來做一個版本 (i.e., 同產品中的後續版本應該在product-version上有區別)

 

3.9 質量值(Quality Values)

HTTP內容協商(content negotiation,12節介紹)運用短「浮點」數字(short floating point number)來表示不同協商參數的相對重要性。重要性的權值被規範化成一個從0到1的實數。0是最小值,1是最大值。如果一個參數的質量值(quanlity value)為0,那麼這個參數的內容對客戶端來說是不被接受。HTTP/1.1應用程序不能產生多於三位小數的實數。下面規則限定了這些值。

       qvalue         = ( "0" [ "." 0*3DIGIT ] )

                      | ( "1" [ "." 0*3("0") ] )

 "質量值" 是一個不當的用詞,因為這些值僅僅表示相對等級。

 

3.10 語言標籤 (Language Tags)

一個語言標籤表徵一種自然語言,這種自然語言能說,能寫,或者被用來人與人之間的溝通。計算機語言明顯不包括在內的。HTTP在Accept-Language和Content-Language頭域裡應用到語言標籤(language tag)。

HTTP語言標籤的語法和註冊和RFC 1766[1]中定義的一樣。總之,一個語言標籤是由一個部分或多部分構成:一個主語言標籤和可能為空的多個子標籤。

        Language-tag      = primary-tag*("-" subtag)

        primary           = 1*8ALPHA

        subtag            = 1*8ALPHA

標籤中不允許出現空格,標籤大小寫不敏感(case-insensitive)。由IANA來管理語言標籤中的名字。典型的標籤包括:

       en, en-US, en-cockney, i-cherokee, x-pig-latin

上面的任意兩個字母的主標籤是一個ISO-639語言的縮寫,並且兩個大寫字母的子標籤是一個ISO-3166的國家代碼。(上面的最後三個標籤是未經註冊的標籤;但是除最後一個之外所有的標籤都會將來註冊)。

 

3.11 實體標籤 (Entity Tags)

實體標籤被用於比較相同請求資源中兩個或更多實體。HTTP/1.1在ETag(14.19節),If-match(14.24節),If-None-match(14.26節)和If-Rang(14.27節)頭域中運用實體標籤。關於它們怎樣被當作一個緩存驗證器(cache validator)被使用和比較在13.3.3節被定義。一個實體標籤由一個給定的晦澀引用字符串(opaque quoted string),還可能前面帶一個弱指示器組成。

      entity-tag = [ weak ] opaque-tag

      weak       = "W/"

      opaque-tag = quoted-string

一個「強實體標籤」如果被一個資源的兩個實體裡共享,那麼這兩個實體必須在字節上等價。

一個「弱實體標籤」是以"W/"前綴的,它可能會被一個資源的兩個實體共享,如果這兩個實體是等價的,並且能彼此替換,並且替換後也不會在語義上發生太大改變。一個弱實體標籤只能用於弱比較(weak comparison)。

在一個特定資源的所有實體版本裡,一個實體標籤必須能唯一。一個給定的實體標籤值可以被用於不同的URI請求的實體。相同實體標籤的值應用於不同URI請求的實體,並不意味著這些實體是等價的。

 

3.12 範圍單位(Range Units)  

HTTP/1.1允許客戶請求響應實體的一部分。HTTP/1.1在Range(14.35節)和Content-Range(14.16節)頭域裡應用範圍單位(range units)。任何實體根據不同結構化單元都能被分解成子範圍

range-unit = bytes-unit | other-range-unit

bytes-unit = "bytes"

other-range-unit = token

HTTP/1.1中定義的唯一的範圍單位是"bytes"。HTTP/1.1實現可能忽略其他單位指定的範圍。

HTTP/1.1被設計允許應用程序實現不依賴於對範圍的瞭解。

4 HTTP消息

4.1 消息類型(Message Types)

HTTP消息由從客戶到服務器的請求消息和從服務器到客戶的響應消息兩部分組成.

              

HTTP-message = Request|Response ;HTTP/1.1

請求(第5節)和響應(第6節)消息利用RFC 822[9]定義的常用消息的格式,這種消息格式是用於傳輸實體(消息的負載)。兩種類型的消息都由一個開始行(start-line),零個或更多個頭域(經常被稱作「頭」),一個指示頭域結束的空行(也就是以一個CRLF為前綴的什麼也沒有的行),最後一個可有可無的消息主體(message-body)組成。

generic-message = start-line

*(message-header CRLF)

CRLF

[ message-body ]

start-line = Request-Line | Status-Line

為了健壯性,服務器應該忽略任意請求行(Request-Line)前面的空行。換句話說,如果服務器開始讀消息流的時候發現了一個CRLF,它應該忽略這個CRLF。

一般一個存在問題的HTTP/1.0客戶端會在POST請求消息之後添加額外的CRLF。為了重新聲明被BNF明確禁止的行為,一個HTTP/1.1客戶端不能在請求前和請求後附加一些不必要的CRLF。 

4.2 消息頭 (Message Headers)

HTTP頭域包括常用頭域(4.5節),請求頭域(5.3節),響應頭域(6.2節)和實體頭域(7.1節)。它們遵循的是RFC822[0]3.1節中給出的同一個常用格式。每一個頭域由一個名字(域名)跟隨一個":"和域值構成。域名是大小寫不敏感的。域值前面可能有任意數量的LWS的。但SP(空格)是首選的。頭域能被延伸多行,這通過在這些行前面加一些SP或HT。應用程序當產生HTTP消息時,應該遵循「常用格式」,因為可能存在一些應用程序,他們不能接收任何常用形式之外的形式。.

message-header = field-name ":" [ field-value ]

field-name = token

field-value = *( field-content | LWS )

field-content = <the OCTETs making up the field-value

and consisting of either *TEXT or combinations

of token, separators, and quoted-string>

filed-content不包括任何前導或後續的LWS(線性空白):線性空白出現在域值(filed-value)的第一個非空白字符之前或最後一個非空白字符之後。前導或後續LWS可能會在不會改變域值語意情況下被刪除。任何出現在filed-content之間的LWS可能在解析域值之前或把這個消息往下流傳遞時會被一個SP代替。.

不同域名的頭域被接收的順序是不重要的。然而,首先發送常用頭域,然後緊接著是請求頭域或者是響應頭域,然後是以實體頭域結束,這樣做是一個好的的方法。  

如果一個頭域的域值被定義成一個以逗號隔開的列表,那麼使用同一個域名(filed-name)的多個消息頭域可能會出現在一些消息中。不改變消息的語義,可以把相同名的多個頭域結合成一個「域名:域值」對的形式,這可以通過把每一個後續的域值加到第一個裡,每一個域值用逗號隔開的算法實現。同名頭域的接收順序對合併的域值的解釋是有重要意義的,所以代理(proxy)當把消息轉發時不能改變域值的順序。

4.3 消息主體 (Message Body)

HTTP消息的消息主體用來承載請求和響應的實體主體(entity-body)的。這些消息主體(message-body)僅僅當被傳輸譯碼頭域(Transfer-Encoding)指明的傳輸編碼(transfer-coding)應用於實體主體(entity-body)時才和實體主體相區別,其它情況消息主體和實體主體相同。傳輸譯碼頭域在14.41節闡述。

     message-body=entity-body|<entity-body encoded as per Transfer-Encoding>

傳輸譯碼頭域被用來指明應用程序的傳輸編碼,它是為了保證消息的安全和合適的傳輸。傳輸譯碼(Transfer-Encoding)頭域是消息的屬性,而不是實體的屬性,因此可能會沿著請求/響應鏈被添加或刪除。(然而,3.6節描述了一些限制當使用某個傳輸編碼時)

什麼時候消息主體(message-body)允許出現在消息中,這根據不同請求和響應來決定的。

請求中消息主體(message-body)的存在是被請求中消息頭域中是否存在內容長度(Content-Length)或傳輸譯碼(Transfer-Encoding)頭域來通知的。一個消息主體(message-body)不能被包含在請求裡如果某種請求方法(見5.1.1節)不支持請求裡包含實體主體(entity-body)。一個服務器應該能閱讀或再次轉發請求裡的消息主體;如果請求方法不允許包含一個實體主體(entity-body),那麼當服務器處理這個請求時消息主體應該被忽略。

對於響應消息,消息裡是否包含消息主體依賴相應的請求方法和響應狀態碼。所有HEAD請求方法的請求的響應消息不能包含消息主體,即使實體頭域出現在請求裡。所有1XX(信息的),204(無內容的)和304(沒有修改的)的響應都不能包括一個消息主體(message-body)。所有其他的響應必須包括消息主體,即使它長度可能為零。

4.4 消息的長度(Message Length)

當消息主體出現在消息中時,一條消息的傳輸長度(transfer-length)是消息主體(message-body)的長度;也就是說在實體主體被應用了傳輸編碼(transfer-coding)後。當消息中出現消息主體時,消息主體的傳輸長度(transfer-length)由下面(以優先權的順序)決定::

1。任何不能包含消息主體(message-body)的消息(這種消息如1xx,204和304響應和任何HEAD方法請求的響應)總是被頭域後的第一個空行(CRLF)終止,不管消息裡是否存在實體頭域(entity-header fields)。

2。如果Transfer-Encoding頭域(見14.41節)出現,並且它的域值是非」「dentity」傳輸編碼值,那麼傳輸長度(transfer-length)被「塊」(chunked)傳輸編碼定義,除非消息因為通過關閉連接而結束。

3。如果出現Content-Length頭域(屬於實體頭域)(見14.13節),那麼它的十進制值(以字節表示)即代表實體主體長度(entity-length,譯註:實體長度其實就是實體主體的長度,以後把entity-length翻譯成實體主體的長度)又代表傳輸長度(transfer-length)。Content-Length頭域不能包含在消息中,如果實體主體長度(entity-length)和傳輸長度(transfer-length)兩者不相等(也就是說,出現Transfer-Encodind頭域)。如果一個消息即存在傳輸譯碼(Transfer-Encoding)頭域並且也Content-Length頭域,後者會被忽略。

4。如果消息用到媒體類型「multipart/byteranges」,並且傳輸長度(transfer-length)另外也沒有指定,那麼這種自我定界的媒體類型定義了傳輸長度(transfer-length)。這種媒體類型不能被利用除非發送者知道接收者能怎樣去解析它; HTTP1.1客戶端請求裡如果出現Range頭域並且帶有多個字節範圍(byte-range)指示符,這就意味著客戶端能解析multipart/byteranges響應。

一個Range請求頭域可能會被一個不能理解multipart/byteranges的HTTP1.0代理(proxy)再次轉發;在這種情況下,服務器必須能利用這節的1,3或5項裡定義的方法去定界此消息。

5。通過服務器關閉連接能確定消息的傳輸長度。(請求端不能通過關閉連接來指明請求消息體的結束,因為這樣可以讓服務器沒有機會繼續給予響應)。

為了與HTTP/1.0應用程序兼容,包含HTTP/1.1消息主體的請求必須包括一個有效的內容長度(Content-Length)頭域,除非服務器是HTTP/1.1遵循的。如果一個請求包含一個消息主體並且沒有給出內容長度(Content-Length),那麼服務器如果不能判斷消息長度的話應該以400響應(錯誤的請求),或者以411響應(要求長度)如果它堅持想要收到一個有效內容長度(Content-length)。

所有的能接收實體的HTTP/1.1應用程序必須能接受"chunked"的傳輸編碼(3.6節),因此當消息的長度不能被提前確定時,可以利用這種機制來處理消息。

消息不能同時都包括內容長度(Content-Length)頭域和非identity傳輸編碼。如果消息包括了一個非identity的傳輸編碼,內容長度(Content-Length)頭域必須被忽略.

當內容長度(Content-Length)頭域出現在一個具有消息主體(message-body)的消息裡,它的域值必須精確匹配消息主體裡字節數量。HTTP/1.1用戶代理(user agents)當接收了一個無效的長度時必須能通知用戶。

 

4.5 常用頭域(General Header Fields)

有一些頭域即適用於請求消息也適用於響應消息,但是這些頭域並不適合傳輸實體。這些頭域只能應用於傳輸消息。

general-header = Cache-Control ; Section 14.9

| Connection ; Section 14.10

| Date ; Section 14.18

| Pragma ; Section 14.32

| Trailer ; Section 14.40

| Transfer-Encoding ; Section 14.41

| Upgrade ; Section 14.42

| Via ; Section 14.45

| Warning ; Section 14.46

常用頭域名能被擴展,但這要和協議版本的變化相結合。然而,如果通信裡的所有參與者都認同新的或實踐性的頭域是常用頭域,那麼它們可能就被賦於常用頭域的語意。不被識別的頭域會被作為實體頭(entity-header)頭域來看待。

5 請求(Request)

一個請求消息是從客戶端到服務器端的,在消息首行裡包含方法,資源指示符,協議版本。

Request = Request-Line ; Section 5.1

*(( general-header ; Section 4.5

| request-header ; Section 5.3

| entity-header ) CRLF) ; Section 7.1

CRLF

[ message-body ] ; Section 4.3

5.1 請求行 (Request-Line)

請求行(Request-Line)是以一個方法標記開始,後面跟隨Request-URI和協議版本(HTTP-Version),最後以CRLF結束。元素是以SP字符分隔。除了最後的CRLF,CR或LF是不被允許的。

      Request-Line =Method SP Request-URL SP HTTP-Version CRLF

5.1.1方法 (Method)

 方法標記(token)指明了在被Request-URI指定的資源上執行的方法。這種方法是大小寫敏感的。

 Method     = "OPTIONS"                     ;9.2節

             | "GET"                        ;9.3節

             | "HEAD"                       ;9.4節

             |"POST"                        ;9.5節

             |"PUT"                         ;9.6節

             |"DELETE"                      ;9.7節

             |"TRACE"                       ;9.8節

             |"CONNECT"                     ;9.9節

             | extension-method

Extension-method = token

資源所允許的方法由Allow頭域指定(14.7節)。響應的返回碼總是通知客戶某個方法對當前資源是否是被允許的,因為被允許的方法能被動態的改變。如果服務器能理解某方法但此方法對請求資源不被允許的,那麼源服務器應該返回405狀態碼(方法不允許);如果源服務器不能識別或沒有實現某個方法,那麼服務器應返回501狀態碼(沒有實現)。方法GET和HEAD必須被所有一般的服務器支持。所有其它的方法是可選的;然而,如果上面的方法都被實現,這些方法遵循的語意必須和第9章指定的相同。

5.1.2請求URL(Request-URI)

Request-URI是一種通用資源標識符(3.2 節),並且它用於指定請求的請求資源。

    Request-URI   ="*" | absoluteURI | abs_path | authotity

Request-URI的四個選項依賴於請求的性質。星號「*」意味著請求不能應用於一個特定的資源,只能應用於服務器本身,並且只能在方法不應用於一個資源的時候才被允許。舉例如下

             OPTIONS  *  HTTP/1.1

當向代理(proxy)提交請求時,絕對URI(absoluteRUI)格式是不可缺少的。代理(proxy)可能會被要求再次轉發請求或者從一個有效的緩存(cache)裡構造響應去響應請求。注意:代理可能轉發請求給另一個代理或直接給被absoluteURI指定的源服務器。為了避免循環請求,代理(proxy)必須能識別所有的服務器名字,包括任何別名,本地的變化值,數字IP地址。一個請求行(Request-Line)的例子如下:

     GET http://www.w3.org/pub/www/TheProject.html HTTP/1.1

為了未來HTTP版本的所有請求能遷移到absoluteURI地址,所有基於HTTP/1.1的服務器必須接受絕對absoluteURI形式的請求,即使HTTP/1.1客戶端只為代理產生絕對absoluteURI請求。

authority格式只被用於CONNECT方法(9.9節).  

Request-URI大多數情況是被用於指定一個源服務器或網關(gateway)上的資源。這種情況下,URI的絕對路徑(abs_path,見3.2.1節)作為Request-URI被傳輸,並且URI網絡位置(authority)必須在Host頭域裡指出。例如:客戶希望直接從源服務器獲取資源,這種情況下,它可能會建立一個TCP連接,此連接是特定於主機「www.w3.org」的80端口的,這時會發送下面行:

   GET  /pub/WWW/TheProject.html  HTTP/1.1

   Host:www.w3.org

接下來是請求的其他部分。注意絕對路徑(absolute path)不能是空的;如果在原始URI裡沒有出現絕對路徑,必須給出"/"(服務器的根)。

Request-URI是以3.2.1節裡指定的格式傳輸。如果Request-URI用"%HEX HEX"[42]編碼,源服務器為瞭解析請求必須能對它進行解碼。服務器接收到一個無效的Request-URI時必須以一個合適的狀態碼響應。

透明代理(proxy)不能重寫接收到的Request-URI裡的「abs_path」部分,當它轉發此請求到下一個內向服務器(inbound server,見1.3術語)時,但除了上面說的把一個空的abs_path用一個」/」代替之外。

註:不重寫的規則是為了防止代理(proxy)改變請求的原意,因為存在源服務器利用非保留(non-reserved)的URI字符為相反的目的 。實現者應該知道某些低於HTTP/1.1版本的代理(proxy)會重寫Request-URI。

5.2請求資源的識別 (The Resource Identified by a Request)

請求資源的精確定位是由請求裡的Request-URI和Host頭域決定的。

如果源服務器不允許資源根據請求的不同主機來區分時,那麼它可以會忽略Host頭域的值,當它決定通過HTTP/1.1請求來識別資源的時候。(在HTTP/1.1裡關於對Host的支持在19.6.1.1節描述了其他的要求)。

一個源服務器如果必須基於請求主機來區分資源(這是因為存在虛擬主機(virtual hosts)和虛擬主機名(vanity host names)),那麼,對HTTP/1.1請求,它必須遵循下面的規則去決定請求的資源:

1. 如果Request-URI是絕對地址(absoluteURI),那麼主機(host)是Request-URI的一部分。任何出現在請求裡Host頭域的值應當被忽略。

2. 假如Request-URI不是絕對地址(absoluteURI),並且請求包括一個Host頭域,則主機(host)由該Host頭域的值決定.

3. 假如由規則1或規則2定義的主機(host)對服務器來說是一個無效的主機(host),則應當以一個400(壞請求)錯誤消息返回。

缺少Host頭域的HTTP/1.0請求的接收者可能會嘗試去利用啟發式的規則(例如:檢查URI路徑是否是特定某個主機)去決定被請求的真正資源。

5.3請求頭域 (Request Header Fields)

請求頭域允許客戶端傳遞請求的附加信息和客戶端自己的附加信息給服務器。這些頭域作為請求的修飾,這和程序語言方法調用的參數語義是等價的。

   請求頭(request-header) = Accept            ;14.1節

                         | Accept-Charset       ;14.2節

                          |Accept-Encoding         ;14.3節 

                          |Accept-Language        ;14.4節 

                          |Authorization       ;14.8節 

                          |Expect                       ;14.20節

                          |From            ;14.22節

                          |Host                ;14.23節

                          |If-Match         ;14.24節

                          |If-Modified-Since       ;14.25節

                          | If-None-Match            ;14.26節

                          | If-Range                 ;14.27節

                          | If-Unmodified-Since   ;14.28節

                          | Max-Forwards        ;14.31節

                          | Proxy-Authorization  ;14.34節 

                          | Range            ;14.35節

                          | Referer           ;14.36節

                          |TE                           ;14.39節

                          | User-Agent           ;14.43節

請求頭域的名字是能被擴展,但只能隨協議版本改變而被擴展。然而新的或實踐性的頭域可以給定請求頭域語義,如果所有通信方都把它看作請求頭域。不能識別的頭域會被看作實體頭域(entity-header)。

6 響應 (Response)

接收和解析一個請求消息後,服務器發出一個HTTP響應消息。

     response   =Status-Line                           ;6.1節

           *(( general-header)                           ; 4.5節

                       | response-header     ;6.2節

                       | entity-header)CRLF)   ;7.1節

                      CRLF

                      [ message-body ]        ;7.2節

6.1 狀態行 (Status-Line)

響應消息的第一行是狀態行(stauts-Line),由協議版本以及數字狀態碼和相關的文本短語組成,各部分間用空格符隔開,除了最後的CRLF序列,中間不允許有CR或LF。

   Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

6.1.1狀態碼與原因短語 (Status Code and Reason Phrase)

Status-Code元素是一個試圖理解和滿足請求的三位數字整數碼,這些碼的完整定義在第十章。原因短語(Reason-Phrase)是為了給出關於狀態碼的簡單的文本描述。狀態碼用於控制,而原因短語(Reason-Phrase)是讓用戶便於閱讀。客戶端不需要檢查和顯示原因短語。

狀態碼的第一位數字定義響應類別。後兩位數字沒有任何分類角色。第一位數字有五種值:

-1xx :報告的         -請求被接收到,繼續處理

-2xx :成功           - 被成功地接收(received),理解(understood),接受(accepted)的動作 。

-3xx :重發           - 為了完成請求必須採取進一步的動作。

-4xx :客戶端出錯     - 請求包括錯的語法或不能被滿足。

-5xx :服務器出錯     - 服務器無法完成顯然有效的請求。

下面列舉了為HTTP/1.1定義的態碼值,和對應的原因短語(Reason-Phrase)的例子。原因短語在這裡例舉只是建議性的----它們也許被一個局部的等價體代替而不會影響此協議的語義。

 Status-Code =

        "100" ; 10.1.1節: 繼續    

           |"101"   ; 10.1.2節: 轉換協議     

           |"200"   ; 10.2.1節: OK

      |"201"   ; 10.2.2節:   已創建          

        |"202"   ; 10.2.3節:   接受         

     |"203"   ; 10.2.4節: 非權威信息   

        |"204"   ;   10.2.5節: 無內容       

        |"205"   ;   10.2.6節: 重置內容      

        |"206"   ;   10.2.7節: 部分內容      

        |"300"   ;   10.3.1節: 多個選擇       

        |"301"   ;   10.3.2節: 永久移動      

       |"302"   ;   10.3.3節: 發現          

        |"303"   ;   10.3.4節: 見其它         

        |"304"   ;   10.3.5節: 沒有被改變                

        |"305"   ;   10.3.6節: 使用代理              

        |"307"  ;   10.3.8節   臨時重發              

       |"400"   ;   10.4.1節: 壞請求                

        |"401"   ;   10.4.2節: 未授權的              

      |"402"   ;   10.4.3節: 必要的支付            

      |"403"   ;   10.4.4節: 禁用                  

      |"404"   ;   10.4.5節: 沒有找到                 

      |"405"   ;   10.4.6節: 方式不被允許        

      |"406"   ;   10.4.7節: 不接受的              

      |"407"   ;   10.4.8節: 需要代理驗證 

      |"408"   ;   10.4.9節: 請求超時              

      |"409"   ;   10.4.10節; 衝突                   

      |"410"   ;   10.4.11節: 不存在                 

      |"411"   ;   10.4.12節: 長度必需          

      |"412"   ; 10.4.13節;先決條件失敗            

      |"413"   ;   10.4.14節: 請求實體太大      

      |"414"   ;   10.4.15節; 請求URI太大      

      |"415"   ;   10.4.16節: 不被支持的媒體類型   

      |"416"   ; 10.4.17節: 請求的範圍不滿足   

      |"417"   ;   10.4.18節: 期望失敗           

      |"500"   ;   10.5.1節:   服務器內部錯誤       

      |"501"   ;   10.5.2節:   不能實現             

      |"502"   ;   10.5.3節:   壞網關                

      |"503"   ;   10.5.4節:   服務不能獲得         

      |"504"   ;   10.5.5節:   網關超時             

      |"505"   ;   10.5.6節:   HTTP版本不支持  

      |擴展碼   

extension-code =3DIGIT

Reason-Phrase = *<TEXT,excluding CR,LF>

HTTP狀態碼是可擴展的。HTTP應用程序不需要理解所有已註冊狀態碼的含義,儘管那樣的理解是很希望的。但是,應用程序必須瞭解由第一位數字指定的狀態碼的類別,任何未被識別的響應應被看作是那個類別的x00狀態碼,未被識別的響應不能被緩存除外。例如,如果客戶端收到一個未被識別的狀態碼431,則可以安全的認為請求有錯,並且它會對待此響應就像它接收了一個狀態碼是400的響應。在這種情況下,用戶代理(user agent)應當把響應的實體展現給用戶,因為實體有可能包括人類可讀的信息,這些信息也許能解釋非正常狀態的原因。

6.2響應頭域 (Response Header Fields)

響應頭域允許服務器傳送響應的附加信息,這些信息不能放在狀態行(Status-Line)裡.。這些頭域給出有關服務器的信息以及請求URI(Request-URI)指定資源的更進一步訪問信息。

   response-header = Accept-Ranges          ; 14.5節

                   |Age         ; 14.6節

                   |Etag            ; 14.19節

                   |Location          ; 14.30節

                   |Proxy-Autenticate     ; 14.33節

                   |Retry-After     ; 14.37節

                   |Server      ; 14.38節

                   |Vary        ; 14.44節

                   |WWW-Authenticate ; 14.47節

響應頭域的名字能依賴於協議版本的變化而擴展。然而,新的或者實踐性的頭域可能會給予響應頭域的語義如果通信所有成員都能識別他們並把他們看作響應頭域。不被識別的頭域被看作實體頭域。

7 實體(Entity)

如果不被請求方法或響應狀態碼所限制,請求和響應消息都可以傳輸實體。 實體包括實體頭域(entity-header)與實體主體(entity-body),而有些響應只包括實體頭域(entity-header)。

在本節中的發送者和接收者是否是客戶端或服務器,這依賴於誰發送或誰接收此實體。

7.1 實體頭域(Entity Header Fields)

實體(entity-header)頭域定義了關於實體主體的的元信息,或在無主體的情況下定義了請求的資源的元信息。有些元信息是可選的;一些是必須的。

entity-header = Allow ; Section 14.7

| Content-Encoding ; Section 14.11

| Content-Language ; Section 14.12

| Content-Length ; Section 14.13

| Content-Location ; Section 14.14

| Content-MD5 ; Section 14.15

| Content-Range ; Section 14.16

| Content-Type ; Section 14.17

| Expires ; Section 14.21

| Last-Modified ; Section 14.29

| extension-header

extension-header = message-header

擴展頭機制允許在不改變協議的前提下定義額外的實體頭域,但不保證這些域在接收端能夠被識別。未被識別的頭域應當被接收者忽略,且必須被透明代理(transparent proxy)轉發。

7.2 實體主體(Entity Body)

由HTTP請求或響應發送的實體主體(如果存在的話)的格式與編碼方式應由實體的頭域決定。

    Entity-body= *OCTET

如4。3節所述,實體主體(entity-body)只有當消息主體存在時時才存在。實體主體(entity-body)從消息主體根據傳輸譯碼頭域(Transfer-Encoding)解碼得到,傳輸譯碼用於確保消息的安全和合適傳輸。

7.2.1類型(Type)

當消息包含實體主體(entity-body)時,主體的數據類型由實體頭域的Content-Type和Content-Encoding頭域確定。這些頭域定義了兩層順序的編碼模型:

    Entity-body:=Content-Encoding( Content-Type( data) )

Content-Type指定了下層數據的媒體類型。Content-Encoding可能被用來指定附加的應用於數據的內容編碼,經常用於數據壓縮的目的,內容編碼是請求資源的屬性。沒有缺省的編碼。

任一包含了實體主體的HTTP/1.1消息都應包括Content-Type頭域以定義實體主體的媒體類型。如果只有媒體類型沒有被Content-Type頭域指定時,接收者可能會嘗試猜測媒體類型,這通過觀察實體主體的內容並且/或者通過觀察URI指定資源的擴展名。如果媒體類型仍然不知道,接收者應該把類型看作」application/octec-stream」。

7.2.2實體主體長度(Entity Length)

消息的實體主體長度指的是消息主體在被應用於傳輸編碼(transfer-coding)之前的長度。4.4節定義了怎樣去確定消息主體的傳輸長度。

8 連接

8.1 持久連接(Persistent Connection)。

8.1.1目的

在沒有持久連接之前,為獲取每一個URL指定的資源都必須建立了一個獨立的TCP 連接, 這就加重了HTTP服務器的負擔,易引起互聯網的阻塞。嵌入圖片與其它相關數據通常使用戶在短時間內對同一服務器進行多次請求。目前針對這些性能問題的分析以及一個原型實現的結果是可以獲得的[26][30]。 HTTP/1.1(RFC2068)實現的實踐過程和度量展現了一個滿意的結果。對其他方法也有了初步探究,如T/TCP [27]。

HTTP持久連接有著諸多的優點:

--- 通過建立與關閉較少的TCP連接,不僅節省了路由器與主機(客戶端,服務器,代理,網關,隧道或緩存)的CPU時間,還節省了主機用於TCP協議控制塊(TCP protocol control blocks)的內存。

--- HTTP請求和響應能在連接上進行管線請求方式。 管線請求方式能允許客戶端執行多次請求而不用等待每一個請求的響應(譯註:即客戶端可以發送請求而不用等待以前的請求的響應到來後再發請求),並且此時只有一個TCP連接被使用,從而提高了效率,減少了時間。

--- 網絡阻塞會被減少,這是由於減少了因TCP連接產生的包的數量並且也由於允許TCP有充分的時間去決定網絡阻塞的狀態。

--- 因為無須在創建TCP連接時的握手上耗費時間,而使後續請求的等待時間減少。

---HTTP改進的越來越優雅,因為報告錯誤不需要關閉tcp連接的代價。將來的HTTP版本客戶端可以樂觀的嘗試利用一個新特性,但是如果和老服務器通信時錯誤被報告,那麼就要用舊的語義進行重新嘗試。

HTTP實現應該實現持久連接。

8.1.2總體操作

HTTP/1.1 與早期HTTP 版本的一個顯著區別在於持久連接是HTTP/1.1的缺省方式。也就是說,除非另有指定,客戶端總應當假定服務器會保持持久連接,即便在收到服務器的出錯響應時也應如此。

持久連接提供了一種可以由客戶端或服務器通知終止TCP連接的機制。利用Connection頭域(14。10節)可以產生終止連接信號。一旦出現了終止連接的信號,客戶端便不可再向此連接提出任何新請求。

8.1.2.1 協商(Negotiation)

除非請求裡Connection頭域中包含「close」連接標記(connection-token),HTTP/1.1服務器總可以認為HTTP/1.1 客戶端想要維持持久連接(persistent connection)。如果服務器想在發出響應後立即關閉連接,它應當發送一個含「close」的Connection頭域。  

一個HTTP/1.1客戶端可能期望連接一直保持開著,但這必須是基於服務器響應裡是否包含一個Connection頭域並且此頭域裡是否包含「close」。如果客戶端不想再繼續維持連接來發送更多請求,那麼它應發送一個值為「close」的Connection頭域。

如果客戶端或服務器中的任一方在Connection頭域裡包含「close」,那麼那個請求就成為這個連接的最後一個請求。

客戶端和服務器不應認為持久連接是低於1.1的HTTP版本所擁有的,除非它被顯式地指明。19.6.2節指出了跟HTTP/1.1客戶端兼容的更多信息。

 

8.1.2.2 管線(pilelining)

支持持久連接(persistent conncetion)的客戶端可以以管線的方式發送請求(即無須等待響應而發送多個請求)。服務器必須按接收請求的順序發送響應。

假定以持久連接方式進行連接,並且假定在連接建立後進行管線方式請求的客戶端應該準 備去重新嘗試連接如果首次管線請求方式嘗試失敗。如果客戶端重新去嘗試連接,那麼,只有在客戶端知道連接是持久連接之後,客戶端才能進行管線發送請求。如 果服務器在響應所有對應的請求之前關閉了連接,客戶端必須準備去重新發送請求。

客戶端不應該利用非等冪的方法或者非等冪的方法序列(見9.1.2節)進行管線方式的請求。否則一個過早的傳輸層連接的終止可能會導致不確定的結果。希望發送非等冪方法請求的客戶端只有接收了上次它發出請求的響應後才能再次發送請求給服務器。

8.1.3代理 (Proxy Servers)

代理是非常重要的,因為代理正確地實現了Connection頭域的屬性,這在14.10節指出了。

代理必須分別向它相連的客戶端或源服務器(或其他的代理)指明持久連接。每一個持久連接只能應用於一個傳輸層連接。

代理不能和一個HTTP/1.0客戶端建立一個HTTP/1.1持久連接(但是參見RFC2068[33]裡的關於許多HTTP/1.1客戶端利用Keep-Alive頭域的問題的討論)。

8.1.4實際考慮 (Practical Considerations)

服務器通常有一個時限值,超過一定時間即不再維持處於非活動的連接。代理會選一個較高的值,因為客戶端很可能會與同一服務器建立多個連接。持久連接方式的採用對於客戶端與服務器來說均未提出任何必須存在超時或給定多長時間的要求。

當客戶端或服務器希望超時時, 它應該優雅的去關閉傳輸連接。客戶端與服務器端應始終注意對方是否終止了傳輸層連接,並適當的予以響應。若客戶端或服務器未能及時檢測到對方已終止了連接,將會造成不必要的網絡資源浪費。

客戶端,服務器,或代理可能在任意時刻會終止傳輸連接。比如,客戶端可能正想發出新的請求,而此時服務器卻決定關閉「閒置」的連接。在服務器看來,連接已經因為閒置被關閉了, 但客戶端認為我正在請求。

這表明客戶端,服務器與代理必須有能力從連接的異步終止事件中恢復。只要請求是等冪的(見9.1.2節),客戶端軟件應該能重新打開傳輸層連接並重試傳輸遺棄的請求序列而不需要用戶進行去交互。對非等冪方法的請求就不能自動重試請求,儘管用戶代理(user agent)可能提供一個人工操作去重試這些請求。用戶代理(user-agent)對應用程序語義理解的確認應該替代用戶的確認。如果再次重試請求序列失敗,那麼就不能再進行自動重試請求了。

服務器儘可能應該至少在每次連接中響應一個請求。除非出於網絡或客戶端的故障,服務器不應在傳送響應的中途斷開連接。  

使用持久連接的客戶端應限制與某一服務器同時連接的個數。單用戶客戶端不應與任一服務器或代理保持兩個以上的連接。代理應該與其它服務器或代理之間維護2*N個連接,其中N是同時在線的用戶數。這些準則是為了改善響應時間和和避免阻塞。

8.2 消息傳送的要求(Message Transmission Requirements)

8.2.1持久連接與流量控制 (Persistent Connections and Flow Control)

HTTP/1.1服務器應保持持久連接並使用TCP流量控制機制來解決臨時過載,而不是在終止連接後指望客戶端的重試。後一方法會惡化網絡阻塞。

8.2.2監視連接中出錯狀態的消息

HTTP/1.1(或更新)客戶端應該當在發送請求的消息主體時同時監視網絡連接是否處於出錯狀態。若客戶端發現了錯誤,它應當立即停止消息主體的的傳送。若消息主體是以塊傳輸編碼方式發送的(3.6節),可以用長度為零的塊和空尾部(trailer)來提前標記報文結束。若消息主體之前有Content-Length頭域,那麼客戶端必須關閉連接。

8.2.3 100狀態碼的用途

100狀態碼(繼續,見10.1.1節)的目的在於允許客戶端,在發送此請求消息主體前,判定服務器是否願意接受發送消息的主體(基於請求的頭域)。 在有些情況下,如果服務器拒絕查看消息主體,這時客戶端發送消息主體是不恰當的或會大大降低效率。

HTTP/1.1客戶端的要求:

--- 若客戶端想要在發送請求消息主體之前等候100(繼續)響應,則它必須發送一個Expect請求頭域(見14.20節),並且值是「100-continue」。

--- 客戶端不能發送一個值是「100-continue」的Expect請求頭域,如果此客戶端不打算發送帶消息主體的請求。

由於存在舊實現,協議允許二義性的情形存在,這在客戶端在發送「Expect:100-continue」後而不一定要接收一個417(期望失敗)狀態碼或著100(繼續)狀態碼時。因此,當一個客戶端發送Expect請求頭域給一個源服務器(可能通過代理),此服務器也沒有以100(繼續)狀態碼響應,那麼客戶端不應該在發送請求消息的主體前無限等待。

HTTP/1.1源服務器的要求:

--- 當接收一個包含值為「100-contitue」的Expect請求頭域的請求時,源服務器必須或者以100(繼續)狀態碼響應從而繼續從輸入流裡接收數據,或者以一個最終的狀態碼響應。源服務器不能在發送100(繼續)狀態碼響應之前接收請求主體。如果服務器以一個終結狀態碼響應後,它可能會關閉傳輸層連接或者它也可能會繼續接收或遺棄剩餘的請求。但是既然它返回了一個終結狀態碼的響應,它就不能再去執行那個請求的方法(如:POST方法,PUT方法)。

--- 如果請求消息不含值為「100-continue」的Expect請求頭域, 源服務器不應發送100(繼續)響應,並且,當請求來自HTTP/1.0(或更早)的客戶端時,服務器也不得發送100(繼續)響應。對此規定有一例外:為了與RFC 2068兼容,源服務器可能會發送一個100(繼續)狀態響應以響應HTTP/1.1的PUT或POSt請求,雖然這些請求中沒有包含值為」100-continue」的Expect請求頭域。這個例外的目的是為了減少任何客戶端因為等待100(繼續)狀態響應的延時,但此例外只能應用於HTTP/1.1請求,並不適合於其他HTTP版本的請求。

--- 若源服務器已經接收到部分或全部請求的消息的主體,源服務器可以不需要發100(繼續)響應。

---一旦請求消息主體被接收和被處理,發送100(繼續)響應的源服務器必須最終能發送一個終結狀態響應,,除非源服務器過早切斷了傳輸層連接。

--- 若源服務器接收到不含值為「100-contitue」的Expect請 求頭域的請求,但該請求含有請求消息主體,而服務器在從傳輸層連接上接收整個請求消息主體前返回一個終結狀態響應,那麼此源服務器不能關閉傳輸層連接直到 它接收了整個請求或者直到客戶端關閉了此連接。否則客戶端可能不會信任接收此響應消息。然而,這一要求不應該被解釋為防止服務器免受拒絕服務攻擊,或者防 止服務器被客戶端攻擊。

對HTTP/1.1代理的要求:

--- 若代理接到一個請求,此請求包含值為「100-continue」的Expect請求頭域,並且代理可能不能確定下一站服務器是否遵循HTTP/1.1或更高版協議,那麼它必須轉發此請求時包含此Expect頭域。

--- 若代理知道下一站服務器版本是HTTP/1.0或更低,則它不能轉發此請求,並且它必須以417(期望失敗)狀態響應。

--- 代理應當維護一個緩存,以記錄最近訪問下一站點服務器的HTTP版本號。

--- 若接收到的請求來自於版本是HTTP/1.0(或更低)的客戶端,並且此請求不含值為「100-continue」的Expect請求頭域,那麼代理不能轉發100(繼續)響應。 這一要求可覆蓋1xx響應轉發的一般規則(參見10.1節)。

8.2.4服務器過早關閉連接時客戶端的行為

如果HTTP/1.1 客戶端發送一條含有消息主體的請求消息,但不含值為「100-continue」的Expect請求頭域,並且如果客戶端沒有直接與HTTP/1.1源服務器相連,並且客戶端在接收到服務器的狀態響應之前看到了連接的關閉,那麼客戶端應該重試此請求。在重試時,客戶端可以利用下面的算法來獲得可靠的響應。

1. 向服務器發起一新連接。

2. 發送請求頭域。

3. 初始化變量R,使R的值為通往服務器的往返時間的估計值(比如基於建立連接的時間),或在無法估計往返時間時設為一常數值5秒。

4. 計算T=R*(2**N),N為此前重試請求的次數。

5. 等待服務器出錯響應,或是等待T秒(兩者中時間較短的)。

6. 若沒等到出錯響應,T秒後發送請求的消息主體。

7. 若客戶端發現連接被提前關閉,轉到第1步,直到請求被接受,接收到出錯響應,或是用戶因不耐煩而終止了重試過程。

在任意點上,客戶端如果接收到服務器的出錯響應,客戶端

--- 不應再繼續發送請求, 並且

--- 應該關閉連接如果客戶端沒有完成發送請求消息。

9 方法定義(Method Definitions)

HTTP/1.1常用方法的定義如下。雖然方法可以被展開,但新加的方法不能被認為與擴展客戶端和服務器共享同樣的語義。

Host請求頭域(見14.23節)必須能在所有的HTTP/1.1請求裡出現。

9.1 安全和等冪(Idempotent)方法

9.1.1安全方法(Safe Methods)

實現者應當知道軟件是代表用戶在互聯網上進行交互,並且應該小心地允許用戶知道任何它們可能採取的動作(action),這些動作可能給他們自己或他人帶來無法預料的結果。

GET和HEAD方法只是執行沒有影響的動作那就是獲取資源。這些方法應該被考慮是「安全」的。可以讓用戶代理調用的其它方法,如:POST,PUT,DELETE,這些方法是特殊的,用戶代理應該知道這些方法可能會執行不安全的動作。

自然的,保證當服務器由於執行GET請求而不能產生副作用是不可能的;實際上,一些動態的資源會考慮這個特性。用戶並沒有請求這些副作用,因此這些副作用對用戶應該是不受影響的。

9.1.2等冪方法(Idempotent Mehtods)

方法可以有等冪的性質因為(除了出錯或終止問題)N>0個相同請求的副作用同單個請求的副作用的效果是一樣(譯註:等冪就是值不變性,相同的請求得到相同的響應結果,不會出現相同的請求出現不同的響應結果)。方法GET,HEAD,PUT,DELETE都有這種性質。同樣,方法OPTIONS和TRACE不 應該有副作用,因此具有內在的等冪性。然而,有可能有多個請求的請求序列是不等冪的,即使在那樣的序列中所有方法都是等冪的。(如果整個序列整體的執行的 結果總是相同的,並且此結果不會因為序列的整體,部分的再次執行而改變,那麼此序列是等冪的。)例如,一個序列是非等冪的如果它的結果依賴於一個值,此值 在以後相同的序列裡會改變。  

根據定義,一個序列如果沒有副作用,那麼此序列是等冪的(假設在資源集上沒有並行的操作)。

9.2 OPTIONS(選項)

OPTIONS方法表明請求想得到請求/響應鏈上關於此請求裡的URI(Request-URI)指定資源的通信選項信息。此方法允許客戶端去判定請求資源的選項和/或需求,或者服務器的能力,而不需要利用一個資源動作(譯註:使用POST,PUT,DELETE方法)或一個資源獲取(譯註:用GET方法)方法。

此方法的響應是不能緩存的.。

如果OPTIONS請求消息裡包括一個實體主體(當請求消息裡出現Content-Length或者Transfer-Encoding頭域時),那麼媒體類型必須通過Content-Type頭域指明。雖然此規範沒有定義如何使用此實體主體,將來的HTTP擴展可能會利用OPTIONS請求的消息主體去得到服務器得更多信息。一個服務器如果不支持OPTION請求的消息主體,它會遺棄此請求消息主體。

如果請求URI是一個星號("*"),,OPTIONS請求將會應用於服務器的所有資源而不是特定資源。因為服務器的通信選項通常依賴於資源,所以」*」請求只能在「ping」或者「no-op」方法時才有用;它幹不了任何事情除了允許客戶端測試服務器的能力。例如:它能被用來測試代理是否遵循HTTP/1.1。

如果請求URI不是一個星號("*"),,OPTIONS請求只能應用於請求URI指定資源的選項。

200響應應該包含任何指明選項性質的頭域,這些選項性質由服務器實現並且只適合那個請求的資源(例如,Allow頭域),但也可能包一些擴展的在此規範裡沒有定義的頭域。如果有響應主體的話也應該包含一些通信選項的信息。這個響應主體的格式並沒有在此規範裡定義,但是可能會在以後的HTTP裡定義。內容協商可能被用於選擇合適的響應格式。如果沒有響應主體包含,響應就應該包含一個值為「0」的Content-Length頭域。

Max-Forwards請求頭域可能會被用於針對請求鏈中特定的代理。當代理接收到一個OPTIONS請求,且此請求的URI為absoluteURI,並且此請求是可以被轉發的,那麼代理必須要檢測Max-Forwards頭域。如果Max-Forwards頭域的值為「0」,那麼此代理不能轉發此消息;而是代理應該以它自己的通信選項響應。如果Max-Forwards頭域是比0大的整數值,那麼代理必須遞減此值當它轉發此請求時。如果沒有Max-Forwards頭域出現在請求裡,那麼代理轉發此請求時不能包含Max-Forwards頭域。

9.3 GET

GET方法意思是獲取被請求URI(Request-URI)指定的信息(以實體的格式)。如果請求URI涉及到一個數據生成過程,那麼這個過程生成的數據應該被作為實體在響應中返回而不是過程的源文本,除非源文本恰好是過程的輸出。

如果請求消息包含 If-Modified-Since,,If-Unmodified-Since,If-Match,If-None-Match或者 If-Range頭域,GET的語義將變成「條件(conditionall) GET」。一個條件GET方法會請求滿足條件頭域的實體。條件GET方法的目的是為了減少不必要的網絡使用,這通過允許利用緩存裡仍然保鮮的實體而不用多次請求或傳輸客戶端已經擁有的實體來實現的。.

如果請求方法包含一個Range頭域,那麼GET方法就變成「部分Get」(partial GET)方法。一個部分GET會請求實體的一部分,這在14.35節裡描述了。 部分GET方法的目的是為了減少不必要的網絡使用,可以允許客戶端從服務器獲取實體的部分數據,而不需要獲取客戶端本地已經擁有的部分實體數據。

GET請求的響應是可緩存的(cacheable)如果此響應滿足第13節HTTP緩存的要求。

看15.1.3節關於GET請求用於表單時安全考慮。

9.4 HEAD

HEAD方法和GET方法一致,除了服務器不能在響應裡返回消息主體。HEAD請求響應裡HTTP頭域裡的元信息(譯註:元信息就是頭域信息)應該和GET請求響應裡的元信息一致。此方法被用來獲取請求實體的元信息而不需要傳輸實體主體(entity-body)。此方法經常被用來測試超文本鏈接的有效性,可訪問性,和最近的改變。.

HEAD請求的響應是可緩存的,因為響應裡的信息可能被緩存用於更新以前那個資源對應緩存的實體.。如果出現一個新的域值指明緩存的實體和當前源服務器上的實體有所不同(可能因為Content-Length,Content-MD5,ETag或Last-Modified值的改變),那麼緩存(cache)必須認為緩存項是過時的(stale)。

9.5 POST

POST 方法被用於請求源服務器接受請求中的實體作為請求資源的一個新的從屬物。POST被設計涵蓋下面的功能。

--已存在的資源的註釋;

--發佈消息給一個佈告板,新聞組,郵件列表,或者相似的文章組。

--提供一個數據塊,如提交一個表單給一個數據處理過程。

--通過追加操作來擴展數據庫。

POST方法的實際功能是由服務器決定的,並且經常依賴於請求URI(Request-URI)。POST提交的實體是請求URI的從屬物,就好像一個文件從屬於一個目錄,一篇新聞文章從屬於一個新聞組,或者一條記錄從屬於一個數據庫。

POST方法執行的動作可能不會對請求URI所指的資源起作用。在這種情況下,200(成功)或者204(沒有內容)將是適合的響應狀態,這依賴於響應是否包含一個描述結果的實體。

如果資源被源服務器創建,響應應該是201(Created)並且包含一個實體,此實體描述了請求的狀態。並且引用了這個新資源和一個Location頭域(見14.30節)。

POST方法的響應是不可緩存的。除非響應裡有合適的Cache-Control或者Expires頭域。然而,303(見其他)響應能被用戶代理利用去獲得可緩存的響應。

 POST 請求必須遵循8.2節裡指明的消息傳送的要求。

參見15.1.3節關於安全性的考慮.

9.6 PUT

PUT方法請求服務器去把請求裡的實體存儲在請求URI(Request-URI)標識下。如果請求URI(Request-URI)指定的的資源已經在源服務器上存在,那麼此請求裡的實體應該被當作是源服務器關於此URI所指定資源實體的最新修改版本。如果請求URI(Request-URI)指定的資源不存在,並且此URI被用戶代理定義為一個新資源,那麼源服務器就應該根據請求裡的實體創建一個此URI所標識下的資源。如果一個新的資源被創建了,源服務器必須能向用戶代理(user agent) 發送201(已創建)響應。如果已存在的資源被改變了,那麼源服務器應該發送200(Ok)或者204(無內容)響應。如果資源不能根據請求URI創建或者改變,一個合適的錯誤響應應該給出以反應問題的性質。實體的接收者不能忽略任何它不理解和不能實現的Content-*(如:Content-Range)頭域,並且必須返回501(沒有被實現)響應。

如果請求穿過一個緩存(cache),並且此請求URI(Request-URI)指示了一個或多個當前緩存的實體,那麼這些實體應該被看作是舊的。PUT方法的響應是不可緩存的。

POST方法和PUT方法請求最根本的區別是請求URI(Request-URI)的含義不同。POST請求裡的URI指示一個能處理請求實體的資源(譯註:此資源可能是一段程序,如jsp裡的servlet) 。此資源可能是一個數據接收過程,一個網關(gateway,譯註:網關和代理的區別是:網關可以進行協議轉換,而代理不能,只是起代理的作用,比如緩存服務器其實就是一個代理),或者一個單獨接收註釋的實體。對比而言,PUT方法請求裡的URI標識請求裡封裝的實體一一用戶代理知道URI意指什麼,並且服務器不能把此請求應用於其它資源(resource)。如果服務器期望請求被應用於一個不同的URI,那麼它必須發送301(永久移動)響應;用戶代理可以自己決定是否重定向請求。

一個單獨的資源可能會被許多不同的URI指定。如:一篇文章可能會有一個URI指定當前版本,而這個URI區別於這篇文章其它特殊版本的URI。這種情況下,對一個通用URI的PUT請求可能會導致其資源的其它URI請求被源服務器重定義。

HTTP/1.1沒有定義PUT方法對源服務器的狀態影響。

PUT請求必須遵循8.2節中的消息傳送的要求。

除非特別指出,PUT方法請求裡的實體頭域應該被用於資源的創建或修改。

9.7 DELETE(刪除)

DELETE方法請求源服務器刪除請求URI指定的資源。此方法可能會在源服務器上被人為的干涉(或通過其他方法)。客戶端不能保證此操作能被執行,即使源服務器返回成功狀態碼。然而,服務器不應該指明成功除非它打算刪除資源或把此資源移到一個不可訪問的位置。

如果響應裡包含描述成功的實體,響應應該是200(OK);如果DELETE動作還沒有執行,應該以202(已接受)響應;如果DELETE請求方法已經執行但響應不包含實體,那麼應該以204(無內容)響應。

如果請求穿過緩存,並且請求URI(Request-URI)指定了一個或多個緩存當前實體,那麼這些緩存項應該被認為是舊的。DELETE方法的響應是不能被緩存的。

9.8 TRACE

TRACE方法被用於激發一個遠程的,應用層的請求消息回路(譯註:TRACE方法讓客戶端測試到服務器的網絡通路,回路的意思如發送一個請返回一個響應,這就是一個請求響應回路,)。最後的接收者也許是源服務器,也許是接收到包含Max-Forwards頭域值為0請求的代理或網關。TRACE請求不能包含一個實體。

TRACE方法允許客戶端去瞭解數據被請求鏈的另一端接收的情況,並且利用那些數據信息去測試或診斷。Via頭域值(見14.45)有特殊的用途,因為它可以作為請求鏈的跟蹤信息。利用Max-Forwards頭域允許客戶端限制請求鏈的長度,這是非常有用的,因為可以利用此去測試代理鏈在無限循環裡轉發消息。

如果請求是有效的,響應應該在實體主體裡包含整個請求消息,並且響應應該包含一個Content-Type頭域值為」message/http」的頭域。此方法的響應不能被緩存。

9.9 CONNECT(連接)

HTTP1.1協議規範保留了CONNECT方法,此方法是為了能用於能動態切換到隧道的代理((如 SSL tunneling [44]).)。

10.狀態碼定義

 每一個狀態碼在下面定義,包括此狀態碼依賴於方法的描述和響應裡需要的任何元信息的描述。

10.1 通知的 1xx

這類狀態代碼指明了一個臨時性的響應,包含一個Status-Line和可選的頭域,並且被一個空行結束(譯註:空行就是CRLF)。這類狀態碼響應沒有必須的頭域。因為HTTP/1.0沒有定義任何1xx狀態碼,所以服務器不能發送一個1xx響應給一個HTTP/1.1客戶端,除了實驗性的目的。

客戶端必須能在一個常規響應之前接受一個或多個1xx狀態,即使客戶端不期望100(繼續)狀態響應。不被客戶端期望的1xx狀態響應可能會被用戶代理忽略。

代理必須能轉發1xx響應,除非代理和它的客戶端的連接關閉了,或者除非代理自己響應請求並產生1xx響應。(例如:如果代理添加了「Expect:100-continue」頭域當轉發請求時,那麼它不必轉發相應的100(繼續)狀態響應。)

10.1.1 100 繼續 (Continue)

100狀態響應告訴客戶端應該繼續請求。100響應是個中間響應,它被用於通知客戶端請求的初始部分已經被接收了並且此請求還沒有被服務器丟棄。客戶端應該繼續發送請求的剩餘部分,或者,如果此請求已經完成了客戶端會忽略此100響應。服務器在接收請求後必須發送一個終結響應。見8.2.3節關於此狀態碼的討論和使用。

10.1.2 101切換協議 (Switching Protocols)

服務器理解和願意遵循客戶端這樣的請求,此請求通過Upgrade消息頭域(見14.42節)指明在連接上應用層協議的改變。 服務器將會切換到響應裡Upgrade頭域裡指明的協議,它會以一個空行結束此101響應。

只有協議切換時能受益協議才應該切換。例如,當傳輸資源時,切換到一個新的HTTP版本比舊的版本要好,或者切換到一個實時的,同步的協議會帶來好處時,這時我們都應該考慮切換。

10.2 成功 2xx

 這類狀態碼指明客戶端的請球已經被服務器成功的接收,理解,並且接受了。

10.2.1 200 OK

此狀態碼指明客戶端請求已經成功了。響應返回的信息依賴於請求裡的方法,例如:

GET      請求資源的相應的實體已經包含在響應裡並返回給客戶端。

HEAD     相應於請求資源實體的實體頭域已經被包含在無消息主體的響應裡。

POST     響應裡已經包含一個實體,此實體描述或者包含此POST動作執行的結果

TRACE    響應裡包含一個實體,此實體包含終端對服務器接收的請求消息。

10.2.2 201 已創建(Created)

請求已經被服務器滿足了並且已經產生了一個新的資源。新創建的資源的URI在響應的實體裡返回,但是此資源最精確的URI是在Location頭域裡給出的。響應應該含有一實體,此實體包含此資源的特性和位置,用戶或用戶代理能從這些特性和位置裡選擇最合適的。實體格式被Content-Type頭域裡媒體類型指定。源服務器必須能在返回201狀態碼之前建立資源。如果動作(譯註:這裡指能創建資源的方法,如POST方法)不能被立即執行,那麼服務器應該以202(接受)響應代替。

一個201響應可以包含一個ETag響應頭域,此頭域的值指明了當前請求變量(譯註:變量的含義見第1.3節「變量」的解釋)也即剛剛創建的資源的實體標籤(entity tag)值,見14.19節。

10.2.3 202 接受(Accepted)

請求已經被接受去處理,但是還沒有處理完成。請求可能會或者不會處理完成,因為存在當處理的過程中拒絕處理的情況。

202響應是有意非擔保性的。它是為了允許服務器可以為其它處理(如:每天執行一次的批處理)接收請求而不需要用戶代理在處理沒有完成之前長期連接到服務器。響應裡的實體應該包含請求當前狀態的聲明並且應該包含一個狀態監視指針或一些用戶期望何時請求被滿足的評估值。

10.2.4 203 非權威信息(Non-Authoritative information)

此狀態碼響應指明響應裡實體頭域元信息不能從源服務器獲而是從本地的或第三方響應副本裡收集的。這些元信息可能是源服務器版本的子集或超集。如,包含一個存在本地的資源註釋信息就可以產生一個源服務器能理解的元信息的超集。利用此響應狀態碼不是必須但是比200(Ok)響應卻更加合適。

10.2.5 204 無內容 (No Content)

服務器已經滿足了請求但並沒有返回一個實體而是返回更新的元信息。此響應可能包含新的或更新的元信息以實體頭域的形式,這些元信息應該相關於請求變量。

利用此204響應,客戶端如果是一個用戶代理,它就可以不用改變引起請求發送的文檔視圖(譯註:如一篇html文檔在瀏覽器裡呈現的樣子)。204狀態響應主要的目的是允許輸入,而不必引起用戶代理當前文檔視圖的改變,儘管一些新的或更新了的元信息可能會應用於用戶代理視圖裡的當前文檔。

204響應不能包含一個消息主體,並且在頭域後包含一個空行結束。

10.2.6 205 重置內容(Reset Content)

205狀態響應是服務器告訴用戶代理應該重置引起請求被發送的文檔視圖。此響應主要的目的是清空文檔視圖表單裡的輸入框以便用戶能輸入其它信息。此響應不能包含一個實體。

10.2.7 206 部分內容(Partial Content)

服務器已經完成了客戶端對資源的部分GET請求。請求必須包含一個Range頭域(14.35節)用來指出想要的範圍,並且也有可能包含一個If-Range頭域(見14.27節)來使請求成為一個條件請求。

206狀態的響應必須包含以下的頭域:

- 或者含有一個Content-Range頭域,此頭域指明了響應裡的範圍;或者含有一個值為「multipart/byteranges」的Content-Type頭域並且每部分包含Content-Range頭域。如果一個Content-Length頭域出現在響應裡,它的值必須是實際傳輸的消息主體的字節數。

- Date頭域

- ETag 和/或 Content-Location頭域,如果這些頭域假設在相同請求的200響應裡也會出現的話。

- Expire,Cache-Control,和/或者Vary頭域,如果這些頭域的域值與以前同一變量響應中的不一樣。

如果206響應是使用了強緩存驗證(見13.3.3)的If-Range請求的結果,那麼此響應不應該包含其他的實體頭域。如果響應是使用了弱緩存驗證的If-Range請求的結果,那麼響應必須不能包含其他的實體頭域;這能防止緩存裡緩存的實體主體與更新頭域之間的不一致性。另外,響應必須包含假設在相同請求的200響應裡的所有實體頭域。

緩存不能把206響應和以前的緩存內容相合併如果ETag或Last-Modified頭域並不能精確匹配,見13.5.4。

一個不能支持Range和Content-Range頭域的緩存不能緩存206(部分的)響應。

10.3 重新定向 3xx.

這類狀態碼指明用戶代理需要更進一步的動作去完成請求。進一步的動作可能被用戶代理自動執行而不需要用戶的交互,並且進一步動作請求的方法必須為GET或HEAD。一個客戶端應該發現無限的重定向循環,因為此循環能產生網絡擁擠。

注意:以前此規範版本建議一個最多能有五個重定向。內容開發者應該知道客戶端可能存在這個限制。

10.3.1 300 多個選擇.(Multiple Choices)

請求資源對應於眾多表現形式中的一個,每個表現形式都有一個特定的位置(location),並且代理驅動協商(agent-driven negotiation)信息(見13章)被提供以便用戶(或用戶代理)能選擇一個更適的表現形式並重定向它的請求到那個表現形式的位置。

除非是HEAD請求,否則300狀態響應應該包含一個實體,此實體包含一個資源特性和位置列表,從這個列表裡用戶或用戶代理能選擇最合適的資源的表現形式。實體格式被Content-Type頭域裡的媒體類型指定。用戶代理選擇最合適的表現形式的行為可能會被自動執行,這依賴於實體格式和自己的能力。然而,此規範並沒有定義自動執行行為的標準。

如果服務器能確定更好的表現形式,它應該為此表現形式在Location頭域裡包含一個特定的URI來指明此表現形式的位置;用戶代理可能會利用此Location頭域自動重定向。300狀態響應是可緩存的除非被特別指明。

10.3.2 301 永久移動 (Moved Permanently)

請求資源被賦於一個新的永久的URI,並且任何將來對此資源的引用都會利用此301狀態響應返回的URI。具有鏈接編輯能力的客戶端應該能自動把請求URI的引用轉到到服務器返回的新的引用下。此響應是能緩存的除非另外聲明。

新的永久URI應該在響應中被Location頭域給定。除非請求方法是HEAD,否則此響應應該包含一個超文本提示和一個指向新URI的超文本鏈接。

如果客戶端接收了一個來自非GET或HEAD請求方法的301響應,那麼用戶代理不能自動重定向請求除非它能被用戶確認,因為這可能會改變請求提交的條件。

注意:當客戶端在接收了301狀態碼響應後,會重定向POST請求,一些已經存在的HTTP/1.0用戶代理會錯誤的把此請求變成一個GET請求。

10.3.3 302 發現(Found)

請求的資源暫時地存放在一個不同的URI下。因為重定向的地址可能有時會被改變,客戶端應該繼續為將來的請求利用請求URI(Request-URI)。302響應是只有在Cache-Control或Expires頭域指明的情況下才能被緩存。

臨時的URI應該在Location頭域裡指定。除非請求方法是HEAD,否則此響應應該包含一個超文本提示和一個指向新URI的超文本鏈接。

如果客戶端接收了一個來自非GET或HEAD請求方法的302響應,那麼用戶代理不能自動重定向請求除非它能被用戶確認,因為這可能會改變請求提交的條件。

注意:RFC1945和RFC2068指定客戶端不能在重定向請求的時候改變請求方法。然而,大多數用戶代理實現會把302響應看成是303響應,從而根據Location頭域值的URI執行GET請求,不管原始的請求方法是什麼。303和307狀態響應的目的是為使服務器明白客戶端期望哪種類型的重定向。

10.3.4 303 見其他(See Other)

請求的響應被放在一個不同的URI下,並且應該用GET方法獲得那個資源。此方法的存在主要是讓POST調用腳本的輸出能使用戶代理重定向到一個選擇的資源。新的URI並不是原始請求資源的代替引用。303響應不能被緩存,但是再次重定向請求的響應應該被緩存。

不同的URI應該在Location頭域裡指定。除非請求方法是HEAD,除非請求方法是HEAD,否則此響應應該包含一個超文本提示和一個指向新URI的超文本鏈接。

注意:許多HTTP/1.1以前版本的用戶代理不能理解303狀態響應。當這些客戶端比較關注於互操作性的時候,302狀態碼應該被代替利用,因為大多用戶代理對302響應的理解就是303響應。

10.3.5 304 沒有改變(Not Modified)

如果客戶端已經執行了條件GET請求,並且訪問服務器的資源是允許的,但是服務器上的文檔並沒有被改變,那麼服務器應該以此狀態碼響應。304響應不能包含一個消息主體(message-body),並且在頭域後面總是以一個空行結束。

此響應必須包含下面的頭域:

- Date,除非14.18.1指明的那些規則下Date是可以遺漏的。如果時鍾不準確的源服務器遵循這些規則,並且代理和客戶端在接收了一個沒有Date頭域的響應後加上了自己的Date(這在RFC 2086裡聲明了,見14.19節),緩存將會正確操作。

- ETag 和/或 Content-Location頭域,如果這些頭域應在相同請求的200響應裡出現的話。

- Expire,Cache-Control,和/或者Vary頭域,如果這些頭域值與以前同一變量響應中的不一致。

如果條件GET請求使用強緩存驗證(見13.3.3節)時,那麼響應不應包含其它實體頭域。當條件GET使用弱緩存驗證時,那麼響應必須不能包含其它實體頭域;這能防止緩存的實體主體與更新的頭域之間的不一致性。

如果一個304響應指示一個沒有被緩存的實體,那麼此緩存必須不用理會此響應,並且以無條件請求重試請求。

如果緩存利用一個接收到的304響應去更新一個緩存項,那麼緩存必須用此響應響應裡任何最新的域值更新緩存項。

10.3.6 305 使用代理 (Use Proxy)

請求資源必須能通過代理訪問,代理的地址在響應的Location頭域裡指定。Location頭域指定了代理的URI。接收者被期望通過代理重試此請求,305響應必須被源服務器產生。

注意:RFC 2068並沒有說明305響應必須重定向一個單獨請求並且只能被源服務器產生。不注意這些限制會有重要的安全後果。

10.3.7 306沒有使用的(unused)

306狀態碼被用於此規範以前的版本,是不再使用的意思,並且此狀態碼被保留。

10.3.8 307臨時重發(Temporary Redirect)

請求的資源臨時存在於一個不同的URI下。由於重新向可能有時會改變,所以客戶端應該繼續利用此請求URI(Request-URI)為將來的請求。307響應只有被Cache-Control或Expire頭域指明時才能被緩存。

臨時URI應該在響應的Location頭域裡給定。否則此響應應該包含一個超文本提示和一個指向新URI的超文本鏈接,因為許多HTTP/1.1以前的用戶代理不能理解307狀態響應。因此,此提示應該包含用戶在新的URI上重試原始請求的必需信息。

如果307狀態響應.對應的請求的方法不是GET或HEAD,那麼用戶代理不能自動重定向此請求除非它能被用戶確認,因為因為這可能會改變請求提交的條件。

10.4 客戶端錯誤 4xx

狀態碼4xx類的目的是為了指明客戶端出現錯誤的情況。除了當響應一個HEAD請求,服務器應該包含一個實體,此實體包含一個此錯誤請求的解釋。此狀態碼對所有請求方法都是適合的。用戶代理應該展示任何響應裡包含的實體給用戶。

如果客戶端發送數據,利用TCP的服務器實現應該小心地確保客戶端確認包含了響應的包(packets)的接收,在服務器關閉此輸入連接前。如果在關閉連接後,客戶端繼續發送數據給服務器,那麼服務器的TCP棧將發送一個重置包給客戶端,這能擦除客戶端非確認的輸入緩衝(input buffers)在這些緩衝被HTTP應用程序讀和解析之前。

10.4.1 400 壞請求(Bad Request)

請求不能被服務器理解,由於錯誤的語法。客戶端不應該在沒有改變請求的情況下重試請求。

10.4.2 401 未授權的 (Unauthorized)

服務器需要對請求進行用戶認證。響應必須包含一個WWW-Authenticate頭域(見14.47),此頭域包含一個適用於請求資源的授權的激勵(challenge)。客戶端會以一個Authorization頭域重試請求。如果請求包含了授權證書,那麼401響應指明對這些證書的授權失敗。如果401響應包含一個和以前響應的同樣激勵,並且用戶代理已經嘗試至少一次的授權,那麼用戶應該被呈現包含在響應裡的實體,因為這些實體可能包含相關的診斷信息。HTTP授權訪問在「HTTP Authentication:Basic and Digest Access Authentication」[43]裡解釋。

10.4.3 402 必需的支付 (Payment Required)

此狀態碼為將來的應用保留。

10.4.4 403 禁用 (Forbidden)

服務器理解此請求,但拒絕滿足此請求。認證是沒有作用的,並且請求不應該被重試。如果請求方法是HEAD並且服務器想讓客戶端知道請求為什麼不能被滿足,那麼服務器起應該在響應實體裡描述此拒絕的原因。如果服務器不希望告訴客戶端拒絕的原因,那麼404狀態碼(Not Found)響應將被使用。

10.4.5 404 沒有找到(Not Found)

服務器並沒有找到任何可以匹配請求URI的資源。沒有跡象表明條件是暫時或永久的。410(Gone)狀態響應應該被使用,如果服務器通過內部配置機制知道一個舊資源永遠不能獲得並且也沒有轉發地址。此狀態碼通常被使用,當服務器不希望精確指出請求為何被拒絕,或者當沒有任何其它響應可用時。

10.4.6 405 方法不被允許(Method Not Allowed)

此狀態碼表示請求行(Request-Line)裡的方法對此資源來說不被允許。響應必須包含一個Allow頭域,此頭域包含以一系列對此請求資源有效的方法。

10.4.7 406 不可接受的 (Not Acceptable)

根據客戶端請求的接受頭域(譯註:如:Accept, Accept-Charset, Accept-Encoding, 或者 Accept-Language),服務器不能產生讓客戶端可以接受的響應。

除非是HEAD請求,否則響應應該包含一個實體,此實體應該包含一個可得的實體特性和位置列表,通過它用戶或用戶代理能選擇最合適自己的。實體格式被媒體類型指定。依賴於此格式和用戶代理的本身能力,選擇最合適的可能會被自動執行。然而,此規範並沒有定義自動執行選擇的標準。

注意:HTTP/1.1服務器被准許根據請求裡的接受頭域會返回不可接受的響應。在一些情況下,這可能更傾向於發送一個406響應。用戶代理被鼓勵觀察到來的響應的頭域來確定此響應是否是可接受的。

如果響應是不可接受的,用戶代理應該暫時停止剩餘數據的接收並且詢問用戶然後去決定進一步的動作。

10.4.8 407 需要代理驗證(Proxy Authentication Required)

此狀態碼和401(Unauthorized)相似,但是指示客戶端首先必須利用代理對自己驗證。代理必須返回一個Proxy-Authenticate頭域(見14.33節),此頭域包含一個適用於代理的授權激勵。客戶端可能利用一個合適的Proxy-Autorization頭域去重試此請求(見14.34節)。HTTP訪問授權在「HTTP Authentication;Basic and Digest Access Authentication」[43]。

10.4.9 408 請求超時(Request Timeout)

客戶端在服務器等待的時間裡不能產生請求。客戶端可能在以後會重試此請求。

10.4.10 409 衝突 (Confilict)

請求不能完成由於和當前資源的狀態衝突。此狀態碼只被允許出現在期望用戶也許能解決 此沖並且能重新提交此請求的情況下。響應主體應該包含足夠的為用戶認識此資源衝突的信息。理想的情況下,響應實體應該包含足夠為用戶或用戶代理解決此問題 的信息;然而,這是也許沒有可能並且也沒有必要。

衝突最可能發生在響應PUT請求的時候。例如,如果版本被使用並且被PUT的實體包含資源的改變,而這些改變會和以前的(第三方的)請求的相衝突,那麼服務器應該使用409響應去指明它不能完成此請求。在這種情況下,此響應的實體可能包含這兩個版本的差異點,響應的實體格式以Content-Type頭域指定。

10.4.11 410 不存在(gone)

請求資源在源服務器上不再可得並且也沒有轉發地址可用。此條件被認為是永久的。具有鏈接編輯能力的客戶端應該在用戶確認後刪除請求URI的引用。如果服務器不知道或不容易去確定條件是否是永久的,那麼此404(沒有發現)狀態響應將被代替利用。響應是可緩存的,除非另外申明。

410響應主要的目的是為了web維護任務,這通過告訴接收者資源已經不可得了並且告訴接收者服務器擁有者已經把那個資源的遠程連接給移除了。對有時間限制的,推銷性的服務,和對不再繼續工作在服務器站點人員的資源,這個事件(410響應)是非常普遍的。它不需要把所有長久不可得的資源標記為「gone」或者保持任意長時間—這需要服務器擁有者自己的判斷

10.4.12 411 長度必需 (Length Required)

服務器拒絕接受請求裡沒有包含Content-Length頭域的請求。客戶端可以重試此請求如果它添加了一個有效的Content-Length頭域,此頭域值指定了請求消息裡消息主體的長度。

10.4.13 412 先決條件失敗 (Precondition Failed)

在一個或多個請求頭域裡指定的先決條件當在服務器上測試為false時返回的響應。此響應允許客戶端把先決條件放放到當前資源的元信息(頭域數據)之上,這樣能防止請求方法被應用於一個非目的性的資源。

10.4.14 413 請求實體太大

服務器拒絕處理請求因為請求實體太大以致達到服務器不願意去處理。服務器可能關閉此連接去防止客戶端繼續請求。

如果條件是暫時的,服務器應該包含一個Retry-After頭域用來指明此條件是暫時的並且指明客戶端應該什麼時候重試。

10.4.15 414 請求URI太長(Request-URI Too Long)

服務器拒絕為請求服務因為此請求URI太長了以至於服務器不能解析。這種情況是很少的,只發生在當客戶端把POST請求不合適地轉換為帶有大量查詢信息的GET請求時。

10.4.16 415 不被支持的媒體類型(Unsupported Media Type)

服務器拒絕為請求服務,因為請求的實體的格式不能被此方法的請求資源所支持。

10.4.17 416 請求範圍不滿足 (Requested Range Not Satisfiable)

服務器返回一個此狀態碼的響應,如果請求包含一個Range請求頭域(見14.35節),並且此頭域裡range-specifier值沒有和已選資源的當前extent值重疊,並且請求沒有包含一個If-Range請求頭域。(對byte-ranges來說,這意味著byte-range-spec的所有first-byte-pos

值大於選擇的資源的當前長度)。

當此狀態碼響應是在byte-range請求返回時,響應應該包含一個Content-Range實體頭域用來指定已選資源的當前長度(見14.16節)。響應不能使用multipart/byteranges媒體類型。

10.4.18 417 期望失敗(Expectation Failed)

Expect請求頭域裡指定的希望不能被服務器滿足,或者,如果服務器是代理,那麼能確定請求不能被下一站(next-hop)服務器滿足。

10.5 服務器錯誤 5xx (Server Error)

這類狀態碼指明服務器處理請求時產生錯誤或不能處理請求。除了HEAD請求,服務器應該包含一個實體,此實體用來解釋錯誤,和是否是暫時或長期條件。用戶代理應該展示實體給用戶。此響應狀態碼能應用於任何請求方法。

10.5.1 500 服務器內部錯誤 (Internal Server Error)

服務器遇到了一個意外條件,此條件防止服務器滿足此請求。

10.5.2 501 不能實現 (Not Implemented)

服務器沒有能力去滿足請求。當服務器不能識別請求方法並且不支持它請求資源的時候,這個響應是很合適的。

10.5.3 502 壞網關 (Bad Gateway)

此響應說明:作為網關或代理的服務器從上游(upstream)服務器接收了一個無效的響應。

10.5.4 503 服務不能獲得(Service Unavailable)

由於服務器暫時地過載或維護,服務器不能處理請求。這就是說這是暫時條件,此條件將會在一些延時後被減輕。延遲的長度可以在Retry-After頭域裡指定。如果沒有Retry-After被給,那麼客戶端應該處理此響應就像它處理500響應一樣。

注意:503狀態碼的存在並不是意指服務器當產生過載時必須利用它。一些服務器可能希望拒絕此連接。

10.5.5 504 網關超時(Gateway Timeout)

作為網關或代理的服務器在不能及時地接收一個從URI指定的上游(upstream)服務器(例如:HTTP,FTP,LDAP服務器)或者其他的輔助性服務器(例如:DNS服務器)的響應。

注意:當DNS查找超時時,一些部署的代理將會返回400或500響應。

10.5.6 505  HTTP版本不支持 (HTTP version Not Supported)

服務器不能支持,或拒絕支持此HTTP協議版本消息。505響應指明服務器不能或不願意完成這樣的請求,這在3.1中描述了。此響應應該包含一個實體,此實體描述了為什麼此協議版本不被支持和其他能被服務器支持的協議版本。

11.訪問認證(Access Authentication)

HTTP提供一些可選的激勵響應(challenge-response)認證(authentication)機制,這些機制能被用於服務器去激勵客戶端請求,使客戶端提供認證信息。常用訪問認證框架,還有「basic」和「digest」認證規範,都在「HTTP Authentication:basic and Digest Access Authentication」[43]規範裡指定。HTTP/1.1規範採用了「激勵(chanllenge)」和「證書(credentials)」的定義。

12.內容協商 (Content Negotiation)

大多數響應包含一個實體,此實體包含人類用戶能理解的信息。通常,希望響應能提供給用戶相應請求的「最可得」(best available)的實體。對服務器和緩存來說,不幸的是,並不是所有的用戶都對這個「最可得」的實體有相同的喜好,並且並不是所有的用戶代理(如web瀏覽器)都能一致的呈現這些實體。所以,HTTP提供了幾個「內容協商」的機制 — 當有多個可得的表現形式的時候,對給定響應去選擇最好的表現形式的過程。

注意:沒有稱做「格式協商」(譯註:「格式」指的是「媒體類型」)的,這是因為選擇的表現形式可能會有相同的媒體類型,但卻根據其它能力(capabilities),例如一種不同的語言。

任何包含一個實體主體的響應應該由受協商來決定,包括錯誤響應。

在HTTP中,有兩種類型的內容協商:服務器驅動協商和代理驅動協商。這兩種類型的協商具有正交性,因此能被單獨使用或聯合使用。一個聯合使用的協商會被叫做透明協商,這發生在當緩存利用源服務器提供的代理驅動協商信息為後續請求提供服務器驅動協商的時候。

12.1 服務器驅動協商(Server-driven Negotiation)

如果響應的最好的表現形式的選擇是通過服務器上的算法來實現,那麼這種方式的協商稱做服務器驅動協商。選擇是基於響應可得的表現形式(根據不同的維度,響應會不同;例如,語言,內容編碼,等等)和請求消息裡特定的頭域或附屬於請求的其他信息(如:網絡客戶端的地址)。

服務器驅動協商是有優點的,當從可行的表現形式裡進行選擇的算法對用戶代理來說描述是比較難的(譯註:代理驅動協商),或者當服務器期望通過第一個響應發送「最好的猜測」(「best guess」)給客戶端時(如果「最好的猜測」對用戶是合適的,能避免後續請求的回路延遲)的時候。為了改善服務器的猜測,用戶代理應該包含請求頭域(Accept,Accept-Language,Accept-Encoding,等等),這些頭域能描述它對響應的喜好。

服務驅動協商有如下缺點:

1.        對服務器來說不可能確切地決定什麼對用戶來說是最好的,因為那需要對用戶代理和響應目的的全面理解(如:用戶到底想把響應展示到屏幕還是打印到紙上?)。

2.        使用戶代理在而每一個請求裡描述它的能力即不高效(假定只有少量的響應卻擁有多個表現形式)也潛在地侵犯用戶的隱私。

3.        使源服務器的實現變得複雜,並且使為請求產生響應的算法實現變得複雜。

4.        可能會限制公有緩存(public cache)為多個客戶請求利用相同響應的能力

HTTP/1.1包含下面的請求頭域來使服務器驅動協商啟動,這些請求頭域描述了用戶代理的能力和用戶喜好:Accept(14.1節),Accept-Charset(14.2節),Accept-Encoding(14.3節),Accept-Language(14.4節),和User-Agent(14.43節)。然而,一些源服務器並不只侷限於這些維度,這些服務器能基於請求的任何方面來讓響應不同,這些方面包括請求頭域之外的信息或在此規範裡沒有定義的擴展頭域信息。

Vary頭域能被用來表達服務器選擇表現形式(representation)利用的參數,表現形式受服務器驅動協商決定的。見14.44節描述了Vary頭域如何被服務器的使用,13.6節描述了Vary頭域如何被緩存的使用。

12.2 代理驅動協商 (Agent-driven Negotiation)

對代理驅動協商來說,在源服務器一個初始響應後,響應的最好表現形式的選擇是被用戶代理執行的。選擇是基於響應的一系列可得的表現形式,這些表現形式被包含在初始響應的頭域或初始響應的實體主體(entity-body)裡,每個表現形式被一個屬於自己的URI指定。從這些表現形式中選擇可能被自動執行(如果用戶代理有能力這樣做)或者被用戶從超文本連接菜單中手工選擇。

代理驅動協商是有優點的,當響應可能只能根據一般用途的維度(如:類型,語義,編碼)而不同的時候,當源服務器不能通過查看請求而判定用戶代理能力的時候,當共有緩存(public cache)被用來分派服務器的承載和減少網絡使用的時候。

代理驅動協商也需要第二次請求去獲得最好表現形式的缺點。第二次請求只有當緩存被使用時才是有效率的。另外,此規範沒有定義用戶代理自動選擇表現形式的機制,雖然它也沒有避免這樣的機制被作為一個擴展使用於HTTP/1.1。

HTTP/1.1定義了300(多個選擇)和406(不接受的)狀態響應來進行代理驅動協商,當服務器不能或不願意利用服務器驅動協商來提供一個不同響應(a varying response)的是時候。

12.3 透明協商(Transparent Negotiation)

透明協商是服務器驅動協商和代理驅動協商的結合體。當一個緩存接收到服務器的響應,並且響應裡提供了一系列可得的表現形式(就像在代理驅動協商裡的響應一樣)並且緩存能理解維度的差異,那麼此緩存變得有能力代表源服務器為那個資源的後續請求去執行服務器驅動協商。

透明協商的優點在於它能分發源服務器的協商工作並且能移除代理驅動協商的第二次請求的延遲,因為緩存能正確的猜測到合適的響應並返回給請求端。

此規範沒有定義透明協商的機制,雖然它也沒有避免任何這樣的機製作為擴展被用於HTTP/1.1。

13 HTTP中的緩存

HTTP通常應用於能通過採用緩存技術提高性能的分佈式信息系統。HTTP/1.1協議包括的許多使緩存儘可能的工作的元素。因為這些元素與協議的其他方面有著千絲萬縷的聯繫,而且他們相互作用、影響,因此有必要分別從方法(methods),頭(headers),響應狀態碼來介紹緩存的基本設計。

如果緩存不能改善性能,他將一無用處。HTTP/1.1中緩存可以在許多情況下排除發送請求和發送完整響應。前者減少了網絡回路的數量;我們利用一個「過期(expiration)」機制來為此目的(見13.2節)。後者減少了網絡應用的帶寬;我們用「驗證(validation)」機制來為此目的(見13.3)。

對行為,可行性,和關閉的操作的要求需要我們能放鬆了語義透明性。HTTP/1.1協議允許服務器,緩存,和客戶端在必要的時候能顯式地降低透明性。然而,因為不透明的操作能混淆非專業的用戶,同時可能和某個服務器應用程序不兼容(例如訂購商品),因此協議透明性在下面情況下才能被放鬆:

-- 當被客戶端或源服務器放鬆時,只能被一個顯式的協議層(protocol-level)請求放鬆

-- 當被緩存或被客戶端放鬆時,只能在出現一個對終端用戶的顯式的警告時才能被放鬆

因此,HTTP/1.1協議提供這些重要的元素:

1.提供了完全語義透明性(full semantic transparency)的特性當被通信所有方需要時

2. 允許源服務器或用戶代理顯式地請求和控制非透明性操作的協議特性

3. 允許緩存給響應綁定警告信息(通過Warning頭域來實現)的協議特性,當這些響應沒有保持語義透明的請求近似性(requested approximation)時

一個基本的原則是客戶端必須能夠發現任何語義透明性的潛在放鬆規則。

注意:服務器,緩存,或者客戶端的實現者可能會面對設計上的決策,它並沒有明確地在此規範裡討論。如果一個決策影響了語義透明性,那麼實現者將會在維持語義透明性上犯錯,除非一個仔細且完整的分析能向我們展示打破透明性帶來的好處。

13.1.1緩存正確性(Cache Correctness)

一個正確的緩存必須能用緩存裡最新的(up-to-date)響應來響應請求(見13.2.5,13.2.6,和13.12),已緩存的響應必須滿足下面的條件: 

1.已緩存的響應已被檢測應與通過源服務器重驗證後返回的響應等價。

2.已緩存的響應是足夠保鮮(fresh)的(見13.2節)。缺省的情況下,這意味著此響應必須滿足客戶端,源服務器,和緩存(見14.9節)的最少嚴格(least restrictive freshness)保鮮要求;如果源服務器指定了保鮮要求,那麼它是源服務器自己的保鮮要求。

如果一個已緩存的響應,由於客戶端和源服務器的最多嚴格(most restrictive freshness)保鮮要求,而不是足夠保鮮的,那麼在仔細考慮的情況下,緩存也許仍然會根據一個合適的警告頭域(見13.15和14.46)返回此已緩存的響應,除非這個響應不被允許(例如:通過」no-store」  cache-directive ,或者通過一個」no-cache」 cache-request-directive;見14.9節)。

3.已緩存的響應是一個合適的304(沒有被改變),305(代理重定向),或 錯誤(4xx或者5xx)響應消息。

如果緩存不能同源服務器通信,如果已緩存的響應能正確的服務於請求,那麼一個正確的緩存應該用它緩存的響應去響應請求;如果不能服務器於此請求,那麼緩存必須能返回一個錯誤或一個警告指示通信失敗。

如果緩存從服務器端接收到一個響應(或者是一個完整的響應,或者一個304(沒有改變)的響應),此響應應該是服務器正常情況下發送到請求的客戶端的響應,並且此響應並不再新鮮,那麼此緩存應該把此響應轉發給請求客戶端而不需要添加一個新的Warning頭域(而不需要移去已經存在的Warning頭域)。緩存並不是簡單的因為傳輸中響應變得陳舊而去嘗試重驗證響應;這可能會導致一個無限的循環。用戶代理接收一個陳舊的但沒有Warning頭域的響應,它應該提示用戶一個警告信息。

13.1.2警告信息(Warnings)

無論何時,緩存返回一個響應,此響應既不是第一手的(first-hand)也不是足夠保鮮(在13.1.1節的條件2),那麼緩存必須利用一個Warning常用頭域來警告產生的影響。Warning頭域和當前定義的警告在14.46節裡描述。這些警告允許客戶端去採取合適的動作。

Warning頭域可能被用於緩存相關的和其他的目的。使用Warning頭域而不是錯誤狀態碼,區別於是否是真正的錯誤。

警告被賦予三位數字警告碼(warn-codes)。第一個數字指明:在一個成功的重驗證之後,警告是否必須或不必從緩存項裡刪除。

1xx 警告描述了響應的保鮮或重驗證狀態,並且這些狀態必須在一個成功重驗證之後刪除。1xx警告碼(warn-codes)可能是由緩存產生的,當驗證一個緩存項時。此警告碼不能被客戶端產生。

2xx 警告描述了實體主體或實體頭域的某些方面的信息,這些信息不能被重驗證修改(例如,一個實體主體的有損壓縮),並且這些信息不能在成功重驗證之後被刪除。

見14.46節關於警告碼的定義。

HTTP/1.0緩存將緩存所有響應中的警告,並且不會刪除第一類警告。被要通往到HTTP/1.0緩存的響應,存在其響應中的警告攜帶一個額外的warning-date域可防止將來的HTTP/1.1接收端信任一錯誤的已緩存的警告。

警告同樣攜帶一個警告文本。此文本可能是任何合適的自然語義(可能基於客戶端請求的Accept頭域),同時包含一個可選擇的關於何種字符集被使用的聲明。

多個警告可能會綁定一個響應(或者被源服務器發送或者被一個緩存發送),並且包括多個警告可以共用一個警告碼。例如,服務器可能會以英語和法語提供相同的警告。

當多個警告綁定一個響應時,有時候不可能把所有的警告都展示給客戶。HTTP版本沒有指定嚴格優先規則去決定哪個警告優先展示和以何種順序去展示,但是可以探索一些方法。

13.1.3緩存控制機制 (Cache-control Mechanism)

HTTP/1.1基本緩存機制(服務器指定過期時間和驗證器)對緩存是隱式指令。某些情況下,服務器或客戶端可能需要給HTTP緩存提供顯式指令。我們利用Cache-Control頭域為此目的。

Cache-Control頭域允許客戶端或服務器在請求或響應裡傳輸多個指令。這些指令常常覆蓋缺省的緩存算法。作為一個常用規則,如果頭域值中存在一個明顯的衝突,那麼最多嚴格解釋(most restrictive interpretation)的頭域值會被應用(也就是說,能保留語義透明性的值)。然而,一些情況下,cache-control指令被顯式地用來削弱語義透明性的近似性(例如,」max-stale」 或者 「public」)。

Cache-control指令在14.9節被描述。

13.1.4顯式用戶代理警告(Explicit User Agent Warnings)

很多用戶代理允許用戶覆蓋基本緩存機制。例如,用戶代理可能允許用戶指定緩存實體(即使實體明顯是陳舊的)永遠不要被驗證。或者,用戶代理可能習慣於給任何請求加上「Cache-Control:max-stale=3600」。用戶代理不應該缺省的執行非透明行為或導致非正常且無效率的緩存行為,但是可以通過一個顯式的用戶動作,代理可能會被顯式地設置去這樣做。

如果用戶已覆蓋基本緩存機制,那麼用戶代理無論何時遇到不能滿足服務器透明性要求(server's transparency requirements)的信息被展現時,用戶代理應該顯式地給用戶以指示(特別是,如果被展現實體被認為是陳舊的)。因為協議通常允許用戶代理去判定響應是否是陳舊,所以此指示只需要實際發生時才被展現。此指示不必是對話框;它應該是一個圖標(例如,一個正在腐爛的魚)或者一些其他的指示器。

如果用戶以某種方式已覆蓋緩存機制,同時這種方式可能非正常地降低了緩存效率,那麼用戶代理應該繼續指示此狀態給用戶(例如,通過一個圖片顯示)以便用戶能謹慎地消費額外資源或忍受額外延遲。

13.1.5規則和警告的例外情況(Exceptions to the Rules and Warnings)

在某些情況下,緩存的操作者可以選擇去設置返回陳舊的響應,即使此響應沒有被客戶端請求。這個決定不應該被輕易決定,但是為了實用性或性能方面的要求可能會這樣做,特別是當緩存和源服務器連接不好時。無能何時當緩存會返回一個陳舊的響應時,緩存必須給此響應做個標記(利用Warning頭域),這樣能使客戶端軟件能提醒用戶可能會存在潛在的問題。

同樣可以允許用戶代理去採取步驟獲得第一手的或保鮮的響應。由於這個原因,如果客戶端顯式地請求第一手的或保鮮的響應,緩存就不應該返回一個陳舊的響應,除非由於技術或策略方面的原因而不能遵守。

13.1.6由客戶控制的行為(Client-controlled Behavior)

當源服務器(退一步講,可以是通過在響應裡添加年齡的中間緩存)是過期信息的主要來源時,在某些情況下,客戶端可能需要控制緩存決定是否返回一個已緩存的響應而不需要通過服務器驗證它。客戶端通過利用一些Cache-Control頭域的指示命令(directives)來達到此目的。

客戶端的請求可能會指定自己願意接受一沒有經過驗證響應的最大年齡(age);指定0值會強迫緩存重驗證所有的響應。客戶端同樣也會指定在響應過期之前的最小保持時間。這兩個選項會增強對緩存行為的限制,因此不能進一步地放鬆緩存語義透明的近似性(approximation of semantic transparency)。

客戶端同樣可能會指定它願意接受(accept)到達的陳舊響應。這放鬆了對緩存的限制,同時這可能違反了源服務器對語義透明性的限制,但是這可以支持脫機操作(disconnected operation),或者高可用性(high availability)當連接不好時。

13.2 過期模型 (Expiration Model)

13.2.1服務器指定過期(Server-Specified Expiratiion)

HTTP緩存會工作的很好,這是因為緩存能完全地避免客戶端對源服務器的請求。避免請求的主要機制是使服務器通過提供一個將來的顯式過期時間(explicit expiration time)以指示響應可以滿足後續的請求。也就是說,緩存能返回一個保鮮(fresh)的響應而不需要和源服務器接觸。

服務器可以給響應賦一個將來的顯式過期時間(explicit expiration time),並確信在過期時間之前實體不會改變。這通常能保持語義透明性,只要服務器對過期時間仔細斟酌。

過期機制只能應用於從緩存構建響應,而不能應用於立即轉發給客戶端的第一手(first-hand,見1.3節術語)響應。

如果源服務器希望強制語義透明的緩存去驗證每個請求,它給顯式過期時間(explicit expiration time)設為過去。這就是說響應總是陳舊的,所以當緩存利用此響應去服務於後續請求時,緩存應該驗證此響應。見14.9.4節,有更嚴格的方式來進行重驗證。

如果源服務器希望強迫任何HTTP/1.1緩存(不管此緩存是怎樣設置的)去驗證每一個請求,源服務器應該利用「must-revalidate」緩存控制指令(見14.9節)。

服務器指定顯式過期時間是通過利用Expires頭域或Cache-Control頭域裡的max-age緩存控制指令。

過期時間不能被用於強制客戶代理去刷新顯示或重載資源;過期的語義只能應用於緩存機制,並且當對資源的發起新請求時,此機制只需檢測此資源的過期狀態。見13.13節,關於緩存和歷史機制的差異。

13.2.2啟發式過期

因為源服務器不能總是提供一個顯式過期時間(explicit expiration time),HTTP緩存通常會賦予一個啟發式過期時間(heuristic expiration time),它採用一種算法,此算法利用其它頭域的值(例如Last-Modified時間)去估計一個合理的過期時間。HTTP/1.1規範沒有提供特定的算法,但是卻加強了算法結果最壞情況的限制。因為啟發式過期時間可能會損壞語義透明性,他們應該被謹慎地使用,並且我們鼓勵源服務器儘可能提供顯式過期時間(explicit expiration times)。

13.2.3年齡(Age)計算

為了瞭解緩存項(譯註:緩存項是用來響應請求的,它包含已緩存的響應實體)是否是保鮮的(fresh),緩存需要知道其年齡是否已超過保鮮壽命(freshness lifetime)。我們在13.2.4節中討論如何計算保鮮壽命,本節討論如何計算響應或緩存項的年齡。

在討論中,我們利用術語「now」來表示「執行計算主機上時鐘的當前值」。使用HTTP協議的主機,特別是運行於源服務器和緩存的主機,應該使用NTP[28] 或其他類似協議來同步其時鐘到全球(globally)精確時間標準上。

HTTP1.1協議要求源服務器儘可能在每個響應裡附加一個Date頭域,並且賦予響應產生的時間(見14.18節)。我們利用術語「date_value」去表示Date頭域的值,這是一種適合於運算操作的表示方法。

當從緩存裡獲取響應消息時,HTTP/1.1利用Age響應頭域來表達響應消息的估計年齡。Age響應頭域值是緩存對響應自從被源服務器產生或重驗證到現在的時間估計值。

實際上,年齡的值是響應從源服務器途徑每一個緩存的逗留時間的總和,再加上響應在網絡路徑上傳輸的時間。

我們用「age_value」來表示Age頭域的值,這是一種適於算術操作的表示方法。

一個響應的年齡(age)可以通過兩種完全獨立的途徑來計算::

1.now - date_value,如果本地時鐘與源服務器時鐘同步的相當好。若結果為負,則取零。

2.age_value,如果途徑響應路徑(response path)的所有緩存均遵循HTTP1.1協議。

如果我們有兩種不同的方法計算響應的年齡,我們可以合併二者如下:

corrected_received_age = max(now – date_value,age_value)

並且只要我們有近似同步時鐘或全HTTP/1.1(all-HTTP/1.1)路徑,就能得到一個可信賴的(保守的)結果。

由於網絡附加延時,會在服務器產生響應與下一個緩存或客戶端接收響應之間產生時間延遲。如果不經修訂,這一延遲會帶來不正常的低年齡。

由於導致產生年齡值的請求是早於年齡值的產生,我們能校正網絡附加延遲通過記錄請求產生的時間。然後,當一個年齡值被接收後,它必須被解釋成相對於請求產生的時間,而不是相對響應接收的時間。不管有多少延遲,此算法會導致保守的結果。所以,我們計算:

      corrected_initial_age = corrected_received_age + (now - request_time)

這裡「request_time」是請求的發送時間。

當緩存收到響應時,年齡計算的算法總結如下:

      /*

       * age_value

      *      is the value of Age: header received by the cache with this response.

       * date_value

       *      is the value of the origin server's Date: header

       * request_time

       *      is the (local) time when the cache made the request

       *              that resulted in this cached response

       * response_time

       *      is the (local) time when the cache received the response

       * now

       *      is the current (local) time

       */

      apparent_age = max(0, response_time - date_value); //緩存收到響應時響應的年齡

      corrected_received_age = max(apparent_age, age_value);

      response_delay = response_time - request_time;

      corrected_initial_age = corrected_received_age + response_delay;

      resident_time = now - response_time; //即收到響應到現在的時間間隔

      current_age   = corrected_initial_age + resident_time;

緩存項(cache entry)的current_age是緩存項從被源服務器最後驗證到現在的時間間隔(以秒記)再加上corrected_initial_age。當從緩存項裡產生一條響應時,緩存必須在響應裡包含一個Age頭域,它的值應該等於此緩存項的current_age值。

Age頭域出現在響應裡說明響應不是第一手的(first-hand)(譯註:第一手的說明,響應是直接來自於源服務器到達接收端的,而不是來自於緩存裡保存的副本)。然而相反的情況並不成立,因為響應裡缺少Age頭域並不能說明響應是第一手的(fisrt-hand),除非所有請求路徑上的緩存都遵循HTTP/1.1協議(也就是說,以前HTTP版本緩存沒有定義Age頭域)。

13.2.4過期計算(Expiration Calculations)

為了確定一條響應是保鮮的(fresh)還是陳舊的(stale),我們需要將其保鮮壽命(freshness lifetime)和年齡(age)進行比較。年齡的計算見13.2.3節,本節講解怎樣計算保鮮壽命,以及判定一個響應是否已經過期。在下面的討論中,數值可以用任何適於算術操作的形式表示。

我們用術語「expires_value」來表明Expires頭域的值。我們用術語「max_age_value」來表示Cache-Control頭域裡「max-age」控制指令的值(見14.9.3節)。

max-age指令優於Expires頭域執行,所以如果max-age出現在響應裡,那麼定義如下:

      freshness_lifetime = max_age_value

否則,若Expires頭域出現在響應裡,定義如下:

      freshness_lifetime = expires_value - date_value

注意上述運算不受時鐘誤差影響,因為所有信息均來自源服務器。

如果Expires, Cache-Control:max-age, 或 Cache-Control:s-maxage (見 14.9.3) 均未在響應中出現,且響應沒有包含對緩存的其他控制,那麼緩存可以用啟發式算法計算保鮮壽命(freshness lifetime)。緩存必須對年齡大於24小時的響應附加113警告,如果此響應不帶這種警告。

同樣,如果響應有最後修改時間(Last-Modified time),啟發式過期值應不大於從那個時間開始到現在這段時間間隔的某個分數。典型設置為間隔的10% 。

計算響應是否過期非常簡單:

 response_is_fresh = (freshness_lifetime > current_age)

13.2.5澄清過期值(Disambiguation Expiration Values)

由於過期值容易被任意設置,有可能兩個緩存包含同一資源的不同保鮮值(fresh values)。

如果客戶端執行獲取請求接收到一個非第一手的響應,此請求響應在客戶端緩存裡仍然是保鮮的,並且緩存項裡的Date頭域的值比新響應的Date頭域值要新,那麼客戶端應該忽略此新響應。如果這樣的話,它可以以「Cache-Control:max-age=0」指令(見14.9節)重試請求,從而去強制和源服務器重驗證。

如果一個緩存對同一個表現形式(representation)擁有兩個保鮮響應卻有不同的驗證器,那麼緩存必須利用Date頭域值最近的響應。這種情況可能發生由於緩存會緩存來自其它緩存的響應,或者由於客戶端已要求重載或重驗證一個顯然保鮮的緩存項的。

13.2.6澄清多個響應(Disambiguating Multiple Response)

因為客戶端可能收到經多個路徑而來的響應,所以某些響應會經過一些緩存集,某些響應會經過其它緩存集,客戶端收到響應的順序可能與源服務器發送響應的順序不同。我們希望客戶端利用最新的響應,即使舊響應仍然是保鮮的。

實體標籤(entity tag)和過期值(expiration value)都不能決定響應的順序,因為可能會出現晚一點的響應故意攜帶過早的過期時間(expiration time)。日期值的精度被規定只有一秒。

當客戶端嘗試重驗證一個緩存項的時,並且接收到的響應裡Date頭域晚於已存在的緩存項,那麼客戶端應該無條件的重試請求,並且包含

       Cache-Control: max-age=0

去強制任何中間緩存通過源服務器來驗證(validate)它們的緩存副本,或者

       Cache-Control: no-cache

去強制任何中間緩存去從源服務器獲得一個新的副本。

13.3 驗證模型(Validation Model)

當緩存擁有一個舊緩存項並且想利用它來作為客戶端請求的響應時,緩存必須首先通過源服務器(或者可能通過一個有保鮮響應的中間緩存)對其進行驗證看是否此緩存項可用。我們稱做「驗證(validating)」此緩存項。我們可以不必花代價來重傳完整響應(full response),並且在緩存項無效時可以不必產生額外的回路,因此HTTP1.1協議支持使用條件方法(conditional methods)。.

協議支持條件方法(conditional methods)的關鍵特徵是圍繞「緩存驗證器(cache validator)」展開的。當源服務器產生一個完整響應(full response)時,它同時會附加一些驗證器給響應,這些驗證器和緩存項一起保存。當客戶端(用戶代理或緩存)對有緩存項的資源執行條件請求時,客戶端在請求裡包含一個相關的驗證器(validator)。

服務器(有可能是源服務器或緩存服務器)核對請求裡的驗證器和當前此實體本地驗證器是否匹配,如果匹配(見13.3.3),則返回一個特定狀態碼(通常為304(沒有改變))的響應並不包含實體主體(entity body)。如果不匹配,服務器就返回完整響應(包含實體主體)。這樣,如果驗證器匹配,我們就避免了傳輸完整響應(full response);同時,如果驗證器不匹配,也避免了額外的回路。

在HTTP1.1協議中,一個條件請求和普通的請求相似,除條件請求攜帶一些特殊的頭域(這些頭域包含驗證器),包含這些特殊的頭域就隱含地表明請求方法(通常是GET方法)為條件請求方法。

協議中緩存驗證條件有正向條件和負向條件。也就是說有存在驗證器匹配,請求方法會執行;驗證器不匹配,請求方法也可能會執行。

注意:缺少驗證器的響應可能會被緩存,而且會被緩存用來為請求提供服務直到緩存副本過期,除非用緩存控制指令顯式地禁止緩存這樣去做。然而,如果緩存沒有實體的驗證器,那麼緩存不能執行條件方法來獲取資源,這就意味著在緩存副本過期之後不會得到刷新。

13.3.1最後修改日期 (Last-Modified Dates)

Last-Modifed實體頭域值經常被用作一個緩存驗證器。簡而言之,如果實體自從Last-Modifed值之後沒有改變,那麼緩存項被認為是有效的。

13.3.2實體標籤緩存驗證器(Entity Tag Cache Validators)

ETag響應頭域值是實體標籤,它提供了一個「晦澀(opaque)」緩存驗證器。當在不方便保存修改日期時,當在HTTP日期值的一秒精度不能滿足需要時,或當源服務器希望避免使用修改日期產生的衝突時,通過實體標籤能得到更可靠的驗證,。

實體標籤在3.11節描述了。使用了實體標籤的頭域在14.19,14.24,14.26和14.44節裡描述了。

13.3.3強,弱驗證器 (Weak and Strong Validators)

由於源服務器和緩存會比較兩個驗證器來確定他們是否代表相同的實體,所以通常希望實體發生任何變化時驗證器也相應變化,這樣的驗證器為強驗證器。.

然而,可能存在這樣的請求,服務器傾向於僅在實體發生重要的語義變化時才改變驗證器,而在實體的某些方面不發生重大改變時就不改變驗證器。在資源變化時驗證器未必變化的驗證器稱為弱驗證器.。

實體標籤通常是強驗證器,但協議提供一種機制來使實體標籤變成弱驗證器。可以認為強驗證器在實體的每一字節變化時而變化,而弱驗證器僅在實體的語義變化時才變化。換言之,我們能認為強驗證器是特定實體的標識,而弱驗證器是同一類語義等價實體的標識。

注: 強驗證器的例子:一個整數他會隨著每次實體發生變化而遞增。一個實體的修改時間,如果以秒為精度,能被看作為弱驗證器,因為在一秒內資源可能改變兩次。對弱驗證器的支持是可選擇的。然而,弱驗證器允許更有效地緩存等價對象。

.

客戶端產生請求並把驗證器包含在一個驗證頭域(validating header fiield)裡時或服務器比較兩個驗證器的時候均用到驗證器。強驗證器可在任何情況下使用,而弱驗證器僅在不依賴於嚴格相等時才可用。當客戶端產生條件GET請求來請求一個完整實體時,任何類型的驗證器都可以使用。然而,子範圍(sub-range)請求時只能使用強驗證器,否則客戶端可能會得到一個不一致的實體。

客戶端可以在發出簡單(非子範圍)GET請求裡既可以利用弱驗證器也可以利用強驗證器。客戶端不能利用弱驗證器在其它的請求形式裡。

HTTP1.1協議定義驗證的唯一功能就是比較。有兩種驗證器比較方法,這依賴於比較的背景是否允許利用弱驗證器。

.

-          強比較方法:如果相等,兩驗證器必須完全一致,並且兩個驗證器都是強驗證器。.

-          弱比較方法:如果相等,兩驗證器必須完全一致,但它們中的任何一個或全部被標明「弱」(「weak」)的不會影響結果。

實體標籤是強驗證器除非它被顯式地標記為弱(weak)的。3.11節給出了實體標籤的語法。

最後修改時間(Last-Modifed頭域的值)被用作請求的驗證器時默認為弱驗證器,除非滿足下列規則才判定它是強驗證器:.

-          此驗證器正在被源服務器用來和當前實體驗證器進行比較,並且

-          源服務器知道相關的實體不會在當前驗證器涵蓋的秒內改變兩次,

或者

-          此驗證器即將被客戶端用於If-Modified-Since 或者 If-Unmodified-Since頭域裡,因為客戶端有一個關於實體的緩存項,並且

-          緩存項包含一個日期值(Date value),日期值給出了源服務器發送源響應的時間,並且

-          Last-Modifed頭域值至少提前於日期值(Date value)60秒。 

或者

-          此驗證器正在被中間緩存通過與其緩存項裡保存的驗證器相比較 ,並且

-          緩存項包含日期值(Date value),它指明了源服務器發送源響應(original response)的時間,並且

-          Last-Modifed頭域值至少提前於日期值(Date value)60秒。

此種方法依賴於以下事實,如果兩個不同響應被源服務器在同一秒內被發出,但這兩個響應都有相同的最後修改時間(Last-Modified time),那麼其中至少有一個響應的日期值和最後修改時間的值(Last-Modifed的值)相等。60秒的限制能保證Date和Last-Modifed的值在不同時鐘或在響應準備期間的不同時刻產生。一個實現可能會利用大於60秒的值,如果它認為60秒太短。

如果客戶端希望執行子範圍(sub-range)請求來請求一個只有最後修改(Last-Modifed)時間但沒有晦澀(opaque)驗證器時,它可能會認為只有最後修改(Last-Modified)時間是強的。

若緩存或源服務器接收到一條件請求,而不是完整響應GET請求時,他必須使用強比較方法去計算條件。

此規定允許HTTP1.1,緩存和客戶端能安全地執行子範圍(sub-range)請求獲得來自HTTP/1.0得來的值。

13.3.4關於何時使用實體標籤和最後修改時間的規則

我們對源服務器,客戶端和緩存採用一套規則和建議來規定不同的驗證器何時被使用,出

於何種目的被使用。

 

HTTP/1.1 源服務器:

-          應發送一個實體標籤驗證器,除非產生此實體標籤不可行。

-          可以發送弱實體標籤來替代強實體標籤,如果使用弱實體標籤能提高性能或者不能發送強實體標籤。

-          應發送一Last-Modifed值如果可以的話,除非打破語義透明性(這可能由於利用此日期於if-Modified-Since頭域裡)會導致嚴重的後果。

換句話說,對http1.1源服務器來說,比較好的做法是同時發送強實體標籤和Last-Modified值。.

為了合法,強實體標籤必須隨相關聯的實體值改變而改變。弱實體標籤應該隨相關聯的實體在語義上發生改變而改變。

注意:為保證語義透明緩存,源服務器必須避免為兩個不同的實體重用某個特定的強實體標籤值,也不能重用某特定弱實體標籤為兩個語義不同的實體。緩存項應該能保持任意長的時間,而不管過期時間(expiraton time),所以不能假設緩存從來不會嘗試利用以前獲得的驗證器來驗證緩存項。

HTTP/1.1 客戶端:

- 若實體標籤被源服務器提供,HTTP/1.1客戶端必須在任何緩存條件請求(利用If-Match或If-None-Match)裡利用實體標籤.。

- 僅Last-Modified值被源服務器提供時,HTTP/1.1客戶端應在非子範圍緩存條件請求(利用If-Modified-Since)裡利用此值。

- 僅Last-Modified值被HTTP/1.0源服務器提供時,HTTP/1.1客戶端可能會在子範圍緩存條件請求(利用If-Unmodified-Since)裡利用此值。

- 如果實體標籤和Last-Modified值都被源服務器提供,HTTP/1.1客戶端應該在緩存條件請求裡利用這兩個驗證器。這允許HTTP/1.0和HTTP/1.1緩存能合適地進行響應。

HTTP/1.1源服務器,當接收到一個條件請求並同時包含Last-Modifed日期(例如,在If-Modified-Since,或If-Unmodified-Since頭域裡)和一個或多個實體標籤(例如在If-Match,If-None-Match,或If-Range頭域裡)作為緩存驗證器時,源服務器不能返回一個304狀態響應(沒有改變)除非這樣作能與請求裡所有的條件頭域一致。

HTTP/1.1緩存,當接收到一個條件請求並且此請求裡同時包含Last-Modified日期和一個或多個實體標籤作為緩存驗證器時,它不能返回一個本地已緩存的響應給客戶端,除非已緩存的響應與請求裡所有條件頭域一致。

注意:這些原理背後的規則是HTTP/1.1服務器和客戶端應在請求和響應裡儘可能傳輸非冗餘的信息。接收這些信息的HTTP/1.1系統將會對這些接收到的驗證器作最保守的假設。

HTTP/1.0客戶端和緩存會忽略實體標籤。通常,Last-Modified值會被這些系統接收和利用,以提供透明性和高效緩存行為,因此HTTP/1.1源服務器這時應提供Last-Modified值。在一下很少的情況,一個Last-Modified值作為驗證器被HTTP/1.0系統使用時會帶來嚴重的後果,這時HTTP/1.1服務器不應提供一個Last-Modified值。

13.3.5非驗證條件(Non-validating Conditionls)

實體標籤背後的原則是只有服務作者才知道資源的語義從而去選擇一個合適的緩存驗證機制,並且任何比字節相等(byte-equality)比較方法複雜的驗證器比較方法都會帶來風險。所以,任何其他的頭域的比較(除了Last-Modified,為了兼容HTTP/1.0)從來不會被用於驗證一個緩存項。

13.4 響應的可緩存性(Response Cacheability)

除非被緩存控制(見14.9節) 指令明確地限制,緩存系統可以將一成功響應作為緩存項,可以返回緩存項裡的響應副本而不需要驗證它如果此副本是保鮮的,並且也可以在驗證成功後返回它。如 果響應既沒有緩存驗證器也沒有顯式過期時間,我們認為它不能被緩存,但是某些緩存可能會違反這個約定(例如,當處於脫機時)。客戶端能經常發現這種來自於 緩存的響應,只需通過把Date頭域值同當前時間作比較。

注意:某些HTTP1.0緩存可能違反這一假設而沒有提示任何警告。

然而,在一些情況下,緩存不適合保存實體,或使緩存的實體服務於後續請求。這可能因為服務的作者認為絕對的語義透明性是有必要的,或著出於安全和隱私考慮。某些緩存控制指令因此被提供是為了讓服務器能指示某些資源實體,或部分實體,不能被緩存。

注意在14.8節裡描述了防止一個共享緩存(shared cache)去保存和返回一個以前包含Authorization頭域請求的響應。

除非緩存控制指令防止響應被緩存,一個接收的響應如果它的狀態碼是200,203,206,300,301或410,那麼此響應應該被緩存保存而且可用於後續的請求,但這必須受過期機制決定。然而,如果緩存不支持Range和Content-Range頭域,那麼它不能緩存206響應(部分內容)響應。

緩存接收到的響應如果是其他的狀態碼(如,302和307),那麼此響應不能被用於服務於後續的請求,除非緩存控制指令或其他的頭域顯式地允許它能這樣做。例如,這些頭域包含下面的頭域:Expires頭域(見14.21);「max-age」,「s-maxage」,「must-revalidate」,「prox-revalidate」,「public」或「private」緩存控制指令(見14.9)。

13.5 從緩存裡構造響應

緩存的目的是為了響應將來的請求而緩存請求的響應信息。在很多情況下,緩存簡單地返迴響應的某部分給請求者。然而,如果緩存擁有一個基於以前響應的緩存項,它可能必須把新響應的部分和它緩存項裡的內容合起來。

13.5.1End-to-end和Hop-by-hop頭域

為定義緩存和非緩存代理的行為,我們將HTTP頭域分成兩類:

-          end-to-end頭域,他們被傳輸給最終請求或響應的接收者。響應裡end-to-end頭域必需作為緩存項的一部分存儲,並且必須在任何緩存項構成響應裡被傳輸。

-          hop-by-hop頭域,他們只對傳輸層連接有意義,並且即不能被緩存保存也不能被代理轉發。

下面的HTTP/1.1頭域是hop-by-hop頭域:

-          Connection

-          Keep-Alive

-          Proxy-Authenticate

-          Proxy-Authorization

-          TE

-          Trailers

-          Transfer-Encoding

-          Upgrade

所有其它被HTTP/1.1定義的頭域均為end-to-end頭域。

其它hop-by-hop頭域必須在Connection頭域(14.10節)裡列出,並將被引進於HTTP/1.1(或後來的版本)裡。

13.5.2不可更改的頭域 (Non-modifiable Headers)

HTTP1.1的某些特徵,如數字認證(Digest Authentication),是基於某些end-to-end頭域。一個透明代理不應該改變end-to-end頭域,除非這些頭域的定義要求或允許這樣做。

一個透明代理不能改變請求或響應裡的下面頭域,而且它不能添加這些頭域到沒有這些頭域的請求或響應裡:

-          Contents-location

-          Content-MD5

-          ETag

-          Last-Modified

一個透明代理不能改變響應裡的下面頭域:

-   Expires

但它可以添加這些頭域如果響應裡沒有這些頭域時。如果一個Expires頭域被添加,它必須等於響應裡Date頭域的值。

一個代理不能在包含no-transform緩存控制指令的消息中改變或添加下面的頭域。

-          Content-Encoding

-          Content-Range

-          Content-Type

一個非透明代理可能會在一個消息裡改變或添加這些頭域如果消息不包含no-transform緩存控制指令,但是如果代理這樣做了,它必須添加一個警告214(轉換被應用)(見14.46節)。

注意:end-to-end頭域的不必要更改可能會導致認證失敗,如果更強的認證機制被應用於後續的HTTP版本中。此認證機制可能依賴於沒有在此列舉的頭域值。

請求或響應裡的Content-Length頭域會根據4.4節的規則被添加或被刪除。一個透明代理必須保留實體主體的entity-length(見7.2.2),雖然它可以改變transfer-length(4.4節)。

13.5.3聯合頭域(Combining Headers)

當一個緩存對服務器發出驗證請求時,而且服務器提供304(沒有改變)響應或206(部分內容)響應時,那麼緩存將構造一個響應發送給請求客戶端。

如果狀態碼是304(沒有改變),緩存利用緩存項裡的實體主體(entity-body)作為客戶端請求響應的實體主體。如果響應狀態碼是206(部分內容)並且Etag或Last-Modified頭域能精確匹配,那麼緩存可能把緩存項裡的內容和接收到的響應裡的新內容合併並且利用最後合併的結果作為輸出響應(見13.5.4)。

緩存項裡的end-to-end頭域被用於構造響應,除了:

-          任何保存的警告碼是1xx(見14.46)的Warning頭域必須從緩存項和轉發的響應裡刪除。

-          任何保存的警告碼是2xx的Warning頭域必須要在緩存項和轉發的響應裡保留。

-          任何304或206響應提供的end-to-end頭域必須替換緩存項的相應頭域

除非緩存決定去刪除緩存項,否則它必須同樣能用接收的響應裡的相應end-to-end頭域去替換緩存項裡的頭域,除了上面描述的Warning頭域。如果輸入響應裡的一個頭域匹配緩存項裡多個頭域,那麼所有這些舊的頭域必須被替換。

也就是說,輸入響應的所有end-to-end頭域會覆蓋緩存項裡所有相應的end-to-end頭域(除了緩存的警告碼是1xx的Warning頭域,它將會被刪除即使沒有被覆蓋)。

注意:此規則允許源服務器去利用304(沒有改變)或一個206(部分內容)響應去更新以前同一實體或子範圍實體響應的任何頭域,雖然它也許不總是有意義或正確。這條規則不允許源服務器去利用304(沒有改變)或206(部分內容)響應去完全地刪除一個以前響應的頭域。

13.5.4聯合字節範圍(Combing Byte Ranges)

一條響應可能僅傳送一個實體主體的某一部分,這是由於請求包含一個或多個Range指定的範圍,或者由於連接會被過早地斷開。在幾次這樣得傳輸後,緩存可能已經接收了同一個實體主體的多個範圍部分。

如果緩存有一個實體的非空子範圍,並且一個輸入(incoming)響應(譯註:輸入響應是進入緩存的響應,輸出響應是從緩存出去的響應)攜帶了另一子範圍,那麼緩存可能會把新的子範圍和已經存在的子範圍聯合起來如果下面兩者同時滿足:

-          輸入響應和緩存項都有緩存驗證器。

-          利用強比較方法使兩個緩存驗證器匹配(見13.3.3)。

如果任何要求不能滿足,緩存必須利用最接近現在(most recent)的部分響應(基於任何響應的Date頭域值,並且會利用輸入響應如果這些Date頭域值相等或丟失了),而且必須丟棄其它的部分信息。

13.6 緩存已協商響應(Caching Negotiated Responses)

使用服務器驅動內容協商(12.1節),會在響應裡添加Vary頭域,並改變緩存利用響應去服務後續請求的條件和過程。見14.44節關於服務器利用Vary頭域的描述。

服務器應利用Vary頭域告訴緩存哪些請求頭域被服務器用於從響應(可緩存的)對應的多個表現形式裡進行選擇,響應由服務器驅動協商決定。Vary頭域裡指定的頭域被稱做選擇請求頭域(selecting request-header)。

當緩存接收到一個後續請求,並且此請求的URI指定了一個或多個(包含一個Vary頭域的)緩存項時,緩存不能利用這個緩存項去構造響應從而服務於新的請求,除非所有出現在新請求裡的選擇請求頭域匹配來自於源請求裡已被緩存保存的選擇請求頭域。

在兩個請求裡,我們定義這兩個選擇請求頭域匹配,如果並且只有第一個請求的選擇請求頭域能被轉換為第二個請求裡的頭域通過添加或刪除線性空白(被允許出現在相應的BNF裡的線性空白)和/或把多個消息頭域結合成一個頭域通過4.2節裡的規則。

一個Vary頭域值是「*」總是不能匹配的,並且後續對那個資源的請求只能合適地被源服務器理解。

如果緩存項裡的選擇請求頭域(selecting request-header)不能匹配新請求的選擇請求頭域,那麼緩存不能利用緩存項去滿足請求除非它能以條件請求把此新請求接力到源服務器並且源服務器返回一個304(沒有改變)的狀態響應,并包含一個實體標籤或一個指明被使用實體的Content-Location頭域。

如果一個緩存的表現形式已擁有實體標籤,那麼轉發請求應是以條件請求發送並且應包含資源對應的所有緩存項的實體標籤於If-None-Match頭域(不匹配則執行方法)裡。這告訴了服務器當前緩存擁有的實體集,以便如果實體集裡的任何實體匹配請求的實體,那麼服務器能利用Etag頭域於304(沒有改變)響應裡,從而去告訴緩存哪個緩存項是合適的。如果新響應的實體標籤匹配已存在的緩存項,那麼新響應應被利用去更新已經存在的緩存項的頭域,而且更新的最後結果必須返回給客戶端。

如果任何已存的緩存項只包含相關實體的部分內容,那麼它的實體標籤不應被包含於If-None-Match頭域裡,除非這個請求是範圍請求並且緩存項能完全滿足請求。

如果緩存接收到一成功響應,響應的Content-Location頭域匹配同一請求URI已存緩存項的Content-Location頭域,並且它的實體標籤不同於已存緩存項的實體標籤,而且它的Date頭域值比已存緩存項更接近當前,那麼已經存在的緩存項不能被返回去響應將來的請求並且將會從緩存裡刪除。

13.7 共享和非共享緩存 (Shared and Non-Shared Caches)

出於安全和保密考慮,有必要區分共享和非共享緩存。非共享緩存是僅供一個用戶訪問,此情況下,訪問性(accessibility)應由適當的安全機制控制。所有其它緩存均被認為是共享的。此協議的其它部分對共享緩存的操作添加限制以防止隱私丟失或訪問控制的失敗。

13.8 錯誤和不完全的響應緩存行為

緩存收到不完整響應(例如響應的字節數比Content-Length頭域指定的值要小)時也可以保存,但是必須把此響應看作部分響應。部分相應可以合併(見13.5.4);合併結果可能是完整響應或仍是部分響應。.緩存在沒有顯式標明響應是部分響應情況下(例如利用206(部分內容)狀態響應)不能把部分響應返回給客戶端。緩存不能使用一個200(OK)狀態碼返回一個部分響應。

如果緩存當試圖重驗證一個緩存項時收到一5xx響應,那麼它既可以將此響應轉發給請求的客戶端,或者執行跟服務器響應失敗一樣。在後面的情況下,它可以返回一個以前的接收的響應,除非緩存項包含一個「must-revalidate」緩存控制指令(見14.9節)。

13.9 GET 和 HEAD 的副作用(Side Effects of GET and HEAD)

除非源服務器顯式地禁止緩存它們的響應,否則緩存對任何資源的GET和HEAD方法不應有導致錯誤的行為的副作用(side effects)如果這些響應來自於緩存。他們可以仍然有副作用,但緩存在決定緩存時不必考慮這些副作用。緩存總是被期望去觀察一源服務器對緩存的顯式限制(explicit restrictions)。

我們注意到此規則的一個例外:有些應用程序習慣於在在GETs和HEADs方法裡使用查詢URLs(在rel_path_part裡包含一個「?」)從而執行帶來很大的副作用的操作,緩存不能把此URIs的響應看作一個保鮮的,除非服務器提供一個顯式過期時間(explicit expiration time)。這就意味著,對這樣的URIs的,來自HTTP/1.0服務器的響應不應被緩存保存。見9.1.1節相關的信息。

13.10 在更新或刪除後的無效性

在源服務器上,某些方法對某資源執行的影響,可能會引起一個或多個已存緩存項的非透明的無效。也就是說,雖然他們可能會繼續是保鮮的,但是他們不能準確的反應出源服務器對那個資源的新請求的響應。

HTTP協議無法保證所有此類緩存項均被標明無效。例如,引起源服務器上資源變化的請求可能不會穿過存有一個緩存項的代理。然而,卻有一些規則幫助減少可能的錯誤行為。

在此節裡,短語「使實體無效(invalidata an entity)」意味著緩存要麼可以刪除它保存的所有的實體的實例,要麼可以把這些實體實例標記為「無效」並在它們可作為後續請求的響應之前進行重驗證。  

一些HTTP方法必須讓緩存去使一個實體無效(invalidate an entity) 。這些實體要麼被請求URI指定,要麼在Location或在Content-Location頭域裡被指定(如果出現的話)。這些方法是:

-          PUT

-          DELETE

-          POST

為了防止服務器攻擊拒絕,一個基於Location或Content-Location頭域裡的URI的無效處理必須只有在URI的host部分和請求URI裡的host部分相同時才被執行。     

一個緩存如果不能理解請求裡的方法,那麼它應該使請求URI指定的任何實體無效。

13.11 強制寫通過( Write-Through Mandatory)

所有可能對源服務器資源進行修改的方法都要寫通過(written through)給源服務器。這通常包括所有除了GET和HEAD的方法。緩存在將此種請求轉發給服務器並獲得相應響應前不能對請求客戶端做出響應。 但這個不能阻礙代理緩存在服務器已發送最終響應(final replay)之前發送100(繼續)響應。

相反的情況(通常叫「寫回」或「拷貝回」緩存)在HTTP1.1中是不允許的,這是由於保持一致的更新是非常困難的,並且在寫回之前也會存在服務器,緩存和網絡故障的問題。

13.12 緩存替換 (Cache Replacement)

如果一個新可緩存(見14.9.2, 13.2.5, 13.2.613.8)響應從一資源被緩存接收,並且同一資源的已存響應已經被緩存保存,那麼緩存應該利用新響應去響應當前請求。緩存可能會把這一新響應放進存儲裡,並且可以,如果它滿足所有其它要求,利用此響應來響應任何將來的請求。如果緩存想把此新響應加進緩存存儲,13.5.3的規則必須應用。

說明:一個新響應如果其Date頭域值比已存已緩存的響應的Date頭域值要舊,那麼它是不可緩存的。

13.13 歷史列表 (History Lists)

用戶代理經常使用歷史機制(history mechanisms),如「後退」按鈕和歷史列表,來重新展示一個會話的先前實體。

歷史機制和緩存機制是不同的。特別是歷史機制不應嘗試給資源當前狀態展示一語義透明視圖。其歷史機制只是為了展示資源獲取當時用戶看到的東西。

默認情況,過期時間(expiration time)沒有應用於歷史機制(history mechanisms)。如果實體仍然在存儲裡,歷史機制應該對其顯示即使其實體已經過期了,除非用戶專門地設置代理去刷新已過期的歷史文檔。

這不能防止歷史機制告訴用戶某視圖可能過期。  

注意:如果歷史機制沒必要地阻止了用戶查看陳舊資源,那麼這會強制服務作者避免利用HTTP過 期控制和緩存控制當他們想利用時。服務作者可以認為用戶不被呈現錯誤消息或警告消息是非常重要的,當他們利用導向按鈕(如回退按鈕)去看以前獲得的資源 時。即使有時這些資源本不應被緩存保存,或應很快過期,用戶界面的考慮可能會強制服務作者去尋求其它防止緩存的方法(例如,「一次性」URLs)為了避免不正確的歷史機制功能的影響。

14 頭域定義  

本節定義了所有HTTP/1.1種標準頭域的語法和語義。對於實體頭域來說,發送者和接收者都既可以指客戶端也可以指服務器,取決於誰發送和誰接收此實體。

14.1  Accept

Accept請求頭域被用於指定哪些媒體類型的響應對請求端是可接受的。Accept頭域被用於指明請求只對某些期望的媒體類型有效,例如請求一個內嵌的圖像。

 Accept         = "Accept" ":"

                        #( media-range [ accept-params ] )

 media-range    = ( "*/*"

                        | ( type "/" "*" )

                        | ( type "/" subtype )

                        ) *( ";" parameter )

 accept-params = ";" "q" "=" qvalue *( accept-extension )

 accept-extension = ";" token [ "=" ( token | quoted-string ) ]

星號」*」字符用於把媒體類型組合成一個範圍,「*/*」指明了所有的媒體類型而「type/*」指明type類型的所有子類型。Media-range可能包含一個媒體類型參數。

每一個media-range可能會跟隨一個或多個accept-params,以「q」參數指明一個相對的喜愛程度的質量因子。通過第一個「q」參數(如果有的話)把accept-params和media-range參數分離。喜愛程度質量因子允許用戶或用戶代理去指明對那個media-range的相對喜愛程度,qvalue的範圍是從0到1(見3.9節)。缺省是q=1。

注意:利用「q」參數名字將媒體類型參數(譯註:media-range裡的parameter)和accept-extension分離開來是基於歷史的實踐。儘管這能防止任何以「q」命名的媒體類型參數應用於media-range裡,但在一個media-range裡使用「q」被認為是不可能發生的,這是因為在IANA的媒體類型註冊表裡是沒有「q」參數的並且在Accept頭域裡利用媒體類型參數也是很少見。將來的媒體類型不被鼓任何以「q」命名的參數註冊。

例子::

 Accept :audio/*;q=0.2 , audio/basic

該例應該被解釋成「我喜歡audio/basic,但是可以給我發送任何audio類型如果它最容易得到,但在喜愛程度質量要下降80%」。

如果沒有Accept頭域出現,那麼會假設客戶端能接受所有媒體類型。如果Accept頭域在請求消息裡出現,並且如果服務器根據聯合Accept頭域值發現它不能發送客戶端可接受的響應,那麼服務器應發送406(不可接受的)響應。

一個更加詳盡的例子如下:

   Accept: text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c

這可能被口頭地解釋成「text/html 和 text/x-c是更喜愛的媒體類型,但是如果他們不存在,那麼發送text/x-dvi實體,但如果text/x-dvi也不存在,那麼發送text/plain實體。」

Media-range能被更具有特殊性的media-range或媒體類型覆蓋。如果多個media-range應用了一個特指的類型,那麼最具有特殊性的應該優先。例如:

   Accept: text/*, text/html, text/html; level=1, */*

擁有下面的優先順序:

1)text/html; level=1

2)text/html

3)text/*

4)*/*

一個媒體類型的喜愛程度質量因子是和一個給定的媒體類型聯繫在一起的,它是由查找能最高優先匹配那個媒體類型的media-range決定的。例如:

 Accept:: text/*; q=0.3, text/html; q=0.7, text/html; level=1,

text/html; level=2; q=0.4, */*; q=0.5

可能會引起下面值被聯繫:

 text/html;level=1         = 1

 text/html                 = 0.7

 text/plain                = 0.3

 image/jpeg                = 0.5

 text/html;level=2         = 0.4

 text/html;level=3         = 0.7

注意:一個用戶代理可能會為一個特定的media-range提供一個缺省的質量值的集合。然而,除非用戶代理是一個不能和其他的呈現代理交互的封閉的系統,否則這個缺省的集合應該可以被用戶可設置的。

14.2  Accept-Charset

Accept-Charset請求頭域可以用來指名哪些字符集的響應對請求端是可接受的。Accept-Charset頭域使客戶端能通知服務器產生哪些能讓客戶端更理解的字符集響應。

Accept-Charset = "Accept-Charset" ":"

              1#( ( charset | "*" )[ ";" "q" "=" qvalue ] )

字符集值在3.4節裡描述。每一個字符集可能被給於一個相聯繫的質量值用來表示用戶對那個字符集的喜愛程度。缺省值是q=1.例如:

Accept-Charset:: iso-8859-5, unicode-1-1;q=0.8

如果特殊值「*」出現在Accept-Charset頭域裡,那麼將匹配任何Accept-Charset頭域裡沒有的字符集(包含ISO-8859-1)。如果Accept-Charset頭域裡沒有出現「*」出現,那麼所有沒有在Accept-Charset頭域裡顯式聲明的字符集的質量值都為0,但是有個例外,那就是如果ISO-8859-1沒有被顯式聲明,那麼它的質量值為1。

如果Accept-Charset頭域沒有出現,那麼缺省情況是任何字符集會接受。如果Accept頭域出現在請求消息裡,並且如果服務器不能發送請求端期望的字符集(Accept-Charset頭域指定的)的響應,那麼服務器應發送一個406(不能接受的)錯誤狀態響應,儘管發送一個不可接受的響應也是允許的。

14.3  Accept-Encoding

Accept-Encoding請求頭域和Accept頭域相似,但Accept-Encoding是限定服務器返回給客戶端可以接受的內容編碼(content-coding,見3.5節)。

        Accept-Encoding = "Accept-Encoding" ":"

                      1#( codings [ ";" "q" "=" qvalue ] )

       codings          = ( content-coding | "*" )

使用的例子如下:

       Accept-Encoding: compress, gzip

       Accept-Encoding:

       Accept-Encoding: *

       Accept-Encoding: compress;q=0.5, gzip;q=1.0

       Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0

服務器判斷一個內容編碼(content-coding)是否是可接受的,是根據Accept-Encoding頭域,並利用下面的規則來決定:

1.如果一個內容編碼(content-coding)在Accept-Encoding頭域裡出現,那麼它是可以接受的(acceptable),除非它的qvalue為0。(這在3.9節裡定義,一個qvalue為0說明是「不可接受的」)

2.如果「*」出現在Accept-Encoding頭域裡,那麼它匹配任何沒有出現在Accept-Encoding頭域裡的可得內容編碼。

3.如果多個內容編碼是可接受的,那麼qvalue為最高的且非0的內容編碼是最喜歡的。

4.「identity」內容編碼總是可接受的,除非qvalue為0,或者Accept-Encoding頭域包含「*;q=0」並且同時沒有包含「identity」內容編碼。如果Accept-Encoding頭域值為空,那麼只有「identity」編碼是可接受的。

如果Accept-Encoding頭域在請求裡出現,並且如果服務器不能發送一個Accept-Encoding頭域裡指定的編碼響應,那麼服務器應該發送一個406(不接受的)錯誤的響應。

如果沒有Accept-Encdong頭域出現在請求消息裡,服務器應該假設客戶端將接受任何內容編碼。在這種情況下,如果「identity」是這些可得的內容編碼中的一個,那麼服務器應利用「identity」內容編碼,除非服務器有附加信息指明其它內容編碼對客戶端是有意義的。

注意:如果請求沒有包含Accept-Encoding頭域,並且如果「identity」內容編碼是不可得,那麼通常能被HTTP/1.0客戶端容易理解的內容編碼(也就是說,「gzip」和「compress」)是更喜愛的;一些不能合適展示消息的老客戶端會發送其它內容編碼。服務器也許同樣能以特定用戶代理或客戶端的信息來做決定。

注意:大多數HTTP/1.0應用程序不能識別或遵循一個內容編碼跟隨一個qvalue。這意味著qvalue可能不能工作,並且不能被允許和x-gzip或x-compress在一起。

14.4  Accept-Language

Accept-Language請求頭域和Accept請求頭域類似,但是它是限定服務器返回給客戶端喜愛的自然語言。

       Accept-Language = "Accept-Language" ":"

                         1#( language-range [ ";" "q" "=" qvalue ] )

       language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )

每個language-range均被賦以一個質量值,它代表用戶對此language-range裡涵蓋語言的喜愛程度。質量值缺省為1,例如:

       Accept-Language: da, en-gb;q=0.8, en;q=0.7

好像在說:「我更喜歡Danish,但是也可以接收British English和其他的English的類型的語言。」一個language-range匹配一個語言標籤如果它能精確和語言標籤相等,或者它能精確匹配標籤前綴,標籤前綴是語言標籤裡字符「-」之前的部分。特殊的「*」字符出現在Accept-Language頭域裡,表明能匹配任何不在此頭域裡的語言標籤。

注意:前綴匹配規則並不是意味著:給語言標籤賦值時,如果用戶理解某一個標籤,那麼他同樣會理解所有以這個標籤作為前綴的所有標籤。這種情況下,前綴規則只是表明可以允許使用前綴標籤匹配。

語言標籤的質量因子是Accept-Language頭域裡匹配此語言標籤的language-range的質量值。如果沒有Accept-Language頭域裡language-range匹配的語言標籤,那麼此語言的質量因子被賦予0。如果沒有Accept-Language頭域出現在請求裡,那麼服務器應該假設所有語言將是請求端可接受的。如果一Accept-Language頭域出現在請求裡,那麼所有質量因子大於0的語言是可接受的。

如果發送一個和用戶喜愛的語言相反,這將在15.1.4裡討論。

由於各個用戶的理解程度不一樣,建議客戶端應用程序應讓用戶對語言的偏好進行選擇。如果客戶不能進行選擇,那麼Accept-Language頭域不能在請求裡給出。

注意:當讓用戶作出選擇時,用戶可能不熟悉上述語言匹配的細節,所以應該提供合適的嚮導。例如,用戶可能會認為選擇「en-gb」會提供任何類型的英語文檔如果British English不可得。在這種情況下,用戶代理應該能建議用戶添加一個「en」去得到最佳匹配行為。

14.5  Accept-Range

Accept-Range響應頭域允許服務器向客戶指明服務器對範圍請求的接受度。

     Accept-Ranges     = "Accept-Ranges" ":" acceptable-ranges

     acceptable-ranges = 1#range-unit | "none"

源服務器如果接受字節範圍請求(byte-range request)那麼可以發送

      Accept-Ranges: bytes

但是不是必須這樣做。客戶端在沒有接收此頭域時也可以產生字節範圍請求(byte-range request)。範圍單位(range units)被定義在3.12節。

服務器如果不能接受任何類型的範圍請求(range request),將會發送

Accept-Ranges:none

去勸告客戶不要嘗試範圍請求(range request)。

14.6  Age

Age響應頭域表示發送者對響應產生(或重驗證)時刻後經過的時間的估計。一個已緩存的響應是保鮮的(fresh)如果此響應的年齡沒有超過它的保鮮壽命(freshness response)。Age值怎樣計算在13.2.3節裡描述了。

                 Age = "Age" ":" age-value

                 age-value = delta-seconds

Age值是十進制非負整數,並且以秒為單位.。

如果緩存接收到一個Age值大於它所能表示的上限,或它的年齡計算出現溢出,那麼它必須傳送Age頭域的值為2147483648 (2^31)。一個包含緩存的HTTP/1.1服務器必須在來自於自身緩存的響應裡包含一個Age頭域。緩存應利用一個至少31位的運算類型。

14.7  Allow

Allow實體頭域中列出了被請求URI(Request-URI)指定的資源所支持的方法。此頭域的目的是嚴格地讓接收端知道資源所適合的方法。在405(方法不被允許)響應中必須出現Allow頭域。

     Allow = "Allow" ":"  #Method

使用示例:

     Allow: GET, HEAD, PUT

這一頭域不能阻止客戶端使用其他方法。但在Allow頭域域中給出的方法應被執行。Allow頭域裡指定的方法是每次請求時被源服務器定義的方法。

Allow頭域裡可以和一PUT請求一起使用,而為了說明新的或改變的資源支持這些方法。服務器不需要去支持這些方法,服務器應包含一個Allow頭域在響應裡並且給出實際支持的方法。

代理(proxy)不能改變Allow頭域即使它沒有理解此頭域裡指定的所有方法,因為用戶代理可能和源服務器通信有其他的意圖。

14.8 Authorization (授權)

用戶代理往往希望通過服務器給自己授權,用戶代理這樣做是通過在請求裡包含一個Authorization請求頭域,但是通常在接收了一個401響應後就沒有必要再讓服務器給自己授權了。Authorization頭域由包含用戶代理對請求資源域的授權信息的證書(credentials)組成。

Authorization = "Authorization" ":" credentials

HTTP訪問授權在「HTTP Authenticatiion:Basic and Digest Access Authentication」[43]中描述。如果一個請求被授權並且一個域(realm)被指定,那麼這個證書應對此域裡所有的其他請求是有效的(假設在此授權模式本身不需要其它例如根據激發值或利用同步時鐘而變化的證書)。

當一個共享緩存(shared cache)(見13.7節)接收一個請求,並且此請求包含一個Authorization頭域時,那麼緩存不能返回此請求相應的響應來響應任何其它的請求,除非下面指定的例外之一發生:

1.如果此響應包含「s-maxage」緩存控制指令,那麼此緩存可以利用此響應來響應後續請求。但是(如果指定的最大年齡過期了)代理緩存必須首先通過源服務器來重驗證此響應,同時利用新請求裡的Authorization請求頭域去讓源服務器給新請求授權。(這是s-maxage定義的行為)。如果響應包含「s-maxage=0」,那麼代理在重利用此響應之前必須總是重驗證它。

2.如果此響應包含「must-revalidate」緩存控制指令,那麼緩存可以利用此響應來響應後續請求。但是如果此響應是陳舊的,那麼所有緩存必須首先通過源服務器重驗證那個響應,同時利用新請求裡的Authorization請求頭域去讓源服務器去給此新請求授權。

3.如果此響應包含「public」緩存控制指令,那麼此響應可以用來響應任何後續的請求。

14.9  Cache-Control

Cache-Control常用頭域被用於指定必須在請求/響應鏈上的被所有緩存機制遵守指令。這些指令指定了防止緩存去幹涉請求或響應的行為。這些指令經常覆蓋缺省的緩存算法。緩存指令是單方向的,因為請求中指令的存在並不意味著同樣的指令必須在響應中出現。

請注意HTTP/1.0緩存可能沒有實現Cache-Control,並且也沒有實現Pragma: no-cache(參見14.32節)。

緩存指令必須被代理或網關通過,不管這些指令對應用程序有多重要,因為這些指令可能對請求/響應鏈上的所有接收者都適用。不可能為一個特定緩存去指定一個緩存指令。

Cache-Control = "Cache-Control" ":" 1#cache-directive

cache-directive = cache-request-directive

| cache-response-directive

cache-request-directive =

"no-cache" ; Section 14.9.1

| "no-store" ; Section 14.9.2

| "max-age" "=" delta-seconds ; Section 14.9.3, 14.9.4

| "max-stale" [ "=" delta-seconds ] ; Section 14.9.3

| "min-fresh" "=" delta-seconds ; Section 14.9.3

| "no-transform" ; Section 14.9.5

| "only-if-cached" ; Section 14.9.4

| cache-extension ; Section 14.9.6

cache-response-directive =

"public" ; Section 14.9.1

| "private" [ "=" <"> 1#field-name <"> ] ; Section 14.9.1

| "no-cache" [ "=" <"> 1#field-name <"> ]; Section 14.9.1

| "no-store" ; Section 14.9.2

| "no-transform" ; Section 14.9.5

| "must-revalidate" ; Section 14.9.4

| "proxy-revalidate" ; Section 14.9.4

| "max-age" "=" delta-seconds ; Section 14.9.3

| "s-maxage" "=" delta-seconds ; Section 14.9.3

| cache-extension ; Section 14.9.6

cache-extension = token [ "=" ( token | quoted-string ) ]

當指令不伴有1#field-name參數出現時,該指令適用於整個請求或響應。當一個指令伴有一個1#field-name參數時,此指令僅應用於被命名的頭域,而不能應用於請求或響應的其他部分。這一機制支持可擴展性;HTTP協議將來的版本的實現可以通過將指令應用於HTTP/1.1中未定義的頭域。

緩存控制指令可分為如下幾類:

-          對什麼是可緩存的限制;這可能只由源服務器指定。

-          對什麼能被緩存保存的限制;這可由源服務器或用戶代理指定。

-          對基本過期機制的改進;這可能由源服務器或用戶代理指定。

-          對緩存重驗證及重載的控制;這可能僅由用戶代理指定。

-          對實體傳輸的控制

-          緩存系統的擴展。

 

14.9.1什麼是可緩存的

缺省情況下,若請求方法、請求頭域和響應狀態碼指明響應為可緩存的,則此響應就是可以緩存的。13.4節總結了可緩存性的這些缺省情況。下列緩存控制響應指令(Cache-Control response deirctives)允許源服務器覆蓋缺省的響應可緩存性:

public

  指明響應可被任何緩存保存,即便該響應通常是不可緩存的或只在非共享緩存裡是可緩存的。(參見14.8節,關於Authorization頭域的更多詳述。)

private

指明響應消息的部分或所有部分是為一個用戶準備的並且不得被共享緩存保存。可以使源服務器可以聲明響應的特定部分來針對某一用戶並且對其他用戶的請求是無效的。一個私有(非共享)緩存可以緩存此響應。

註:詞語「私有」的使用僅用來控制響應在何處可被緩存,並且不能保證消息內容的隱私。

no-cache

   如果no-cache緩存控制指令沒有指定一個field-name,那麼一個緩存不能利用此響應在沒有通過源服務器對它進行成功重驗證的情況下去滿足後續的請求。這允許源服務器去防止響應被緩存保存,即使此緩存已被設置可以返回陳舊響應給客戶端。

如果no-cache緩存控制指令指定一個或多個field-name,那麼緩存可以利用此響應去滿足後續的請求,但這要受限於對緩存的其它限制。然而,指定的filed-name必須不能在後續請求的響應裡被發送如果此響應沒有在源服務器那裡得到成功重驗證。這允許源服務器能防止緩存去重利用響應裡的某些頭域,但仍然允許緩存能保存響應剩餘部分。

注意:大多數HTTP/1.0緩存將不能識別或遵循這個指令。

14.9.2什麼能被緩存保存

no-store

no-store緩存控制指令的目的在於防止不經意地釋放或保留敏感信息(比如存放在備份磁帶的信息)。 no-store緩 存控制指令應用於整個消息,並且可以在響應裡或在請求裡被發送。如果在請求裡被發送,緩存不能保存此請求或此請求響應的任何部分。如果在響應裡被發送,緩 存不能保存此響應或保存此響應請求的任何部分。此緩存控制指令能應用於非共享緩存和共享緩存。「不能保存」在這個背景裡的意思是指緩存不能有意地把信息保 存在非易失性存儲裡,而且必須盡力去刪除易失性存儲上的信息當它轉發完畢後。

即使當此指令在一個響應裡時,用戶也可能會顯式地在緩存系統之外保存這個響應(例如,利用一個「另存為」對話框)的地方。歷史緩衝(History buffers)(見13.13節)可能保存這個響應作為它們正常操作的一個部分。

此 指令的目的是為了滿足某些用戶聲明的要求,還有就是為那些比較在意通過訪問緩存數據結構而發生信息洩漏的作者提供方便。在一些情況下,利用此緩存控制指令 可能會增強隱私,但是我們注意到它並不是在任何情況下都是可信任的或都能充分地保護隱私的。特別是,惡意的或被損壞的緩存可能不能識別到或遵循此指令,並 且網絡通信也容易隨時受到竊聽。

14.9.3對基本過期機制的改進

實體的過期時間可由源服務器利用「Expires」頭域(參見14.21節)指定。 或者,也可以在響應裡利用max-age緩存控制指令指定。當max-age緩存控制指令出現在一個已緩存的響應裡時,如果此響應的當前年齡(current age,譯註:見13.2.3節關於current age的定義)大於為那個資源的一個新請求時max-age裡給定的年齡值(以秒),那麼這個已緩存的響應是陳舊的(stale)。對在一個響應裡應用max-age緩存控制指令意味著此響應是可緩存的(也就是說「公有的」)除非出現其它更具限制性的緩存控制指令於響應裡。

若響應同時含有Expires頭域和max-age緩存控制指令,那麼max-age緩存控制指令應該覆蓋Expires頭域,即使Expires頭域更具限制性。此規則允許源服務器可以為一給定響應來為一HTTP/1.1(或更遲)緩存提供一個比一HTTP/1.0緩存更長的過期時間(expiration time)。這個規則可能會很有用,如果某個HTTP/1.0緩存不恰當地計算了年齡(ages)或過期時間(expiration times),可能由於不同步的時鐘。

許多HTTP/1.0緩存實現可能會把響應裡小於或等於該響應裡Date頭域值的Expires頭域值看成與「no-cache」緩存控制響應指令等效。如果一個HTTP/1.1緩存接收到這樣一個響應,並且此響應沒有包含一個Cache-Control頭域,緩存應把此響應看成一個不可緩存的,這是為了保持和HTTP/1.0服務器兼容。  

注意:一個源服務器可能希望把一個相對較新的HTTP緩存控制特性,例如「private」緩存控制指令,用於一個存有不能理解此特性的舊的緩存的網絡上。源服務器應該需要把新特性和響應裡值小於或等於Date值的Expires頭域聯合起來,這樣以便防止舊緩存不恰當地保存此響應。

s-maxage

   如果一響應包含一s-maxage緩存控制指令,那麼對於一共享緩存(不能對私有緩存)來說,s-maxage指定的值將會覆蓋max-age緩存控制指令或Expires頭域。s-maxage緩存控制指令照樣意指proxy-revalidate緩存控制指令(見14.9.4節)的語義,也就是說,共享緩存在沒有通過源服務器首先重驗證這個已陳舊的緩存項時不能利用它來響應後續的請求。s-maxage緩存控制指令總是被私有緩存忽略。

注意:大多數不遵循此規範的老的緩存沒有實現任何緩存控制指令。 一個源服務器如果希望利用一緩存控制指令去限制(但不能阻止)遵循HTTP/1.1的緩存去進行緩存處理,那麼它可能會採用max-age控制指令去覆蓋Expires頭域,並且它會承認HTTP/1.1以前版本的緩存不會去觀察max-age緩存控制指令。

其它緩存控制指令允許一個用戶代理(user agent)去改變基本的過期機制。這些指令可能會被指定在請求裡:

max-age

  表明客戶端願接受這樣一個響應,此響應的年齡不大於客戶端請求裡max-age指定時間(以秒為單位)。除非max-stale緩存控制指令也包含在請求裡,否則客戶端是不能接收一個陳舊響應的。

min-fresh

表明客戶端願接受一個這樣的響應,其保鮮壽命不小於響應當前年齡(current age,見13.2.3節關於current_age的定義)與客戶端請求裡的min-fresh指定的時間之和(以秒為單位)。也就是說,客戶端想要一個響應至少在min-fresh指定的時間內是保鮮的。

max-stale

  表明客戶端願接受已經過期的響應。 若客戶端請求為max-age指定了一個值,則表明客戶端願意接受過期時間不超過在max-stale裡指定秒數的響應。若max-stale沒有賦值,則客戶端願接受任意年齡的陳舊響應。

由於max-stale緩存控制指令出現在請求裡,或由於此緩存被設置成能覆蓋響應的過期時間,導致緩存返回了一個陳舊響應,那麼緩存必須把一個Warning頭域放進這個陳舊響應裡,此Warning頭域裡應該是110警告碼(響應是陳舊的)。

一個緩存可以被設置為可以不需要驗證就可以返回陳舊的響應,但這不應與任何關於緩存驗證(例如,一個「must-revalidate」緩存控制指令)的「必須」等級的要求相衝突。

若新請求與緩存項都包含一個「max-age」緩存控制指令,那麼取兩個值的小者來為此請求決定緩存項的保鮮程度。

14.9.4緩存重驗證和加載控制(Cache Revalidation and Reload Controls)

有時,用戶代理可能希望或出於需要,堅持要求某緩存通過源服務器去重驗證其緩存項,或者要求其緩存從源服務器那裡重新加載其緩存項。End-to-end重驗證也許是有必要的,如果緩存或源服務器已過高估計已緩存的響應(cached response)的過期時間。End-to-end重新加載可能是必要的,如果緩存項由於某原因已經變得陳舊了。

End-to-end重驗證可能被請求,當客戶端沒有本地緩存副本,此時我們稱之為「未指定的end-to-end重驗證(unspecified end-to-end revalidation)」,或者,當客戶端存有本地緩存副本,此時我們稱之為「指定的end-to-end重驗證(specific end-to-end revalidation)」。

利用緩存控制請求指令,客戶端能指定下面三種動作:

End-to-end reload (End-to-end重新加載)

請求包含「no-cache」緩存控制指令,或,為了兼容HTTP/1.0客戶端,「Pragma: no-cache」緩存控制指令。頭域名不能被包含在請求的no-cache緩存控制指令裡。服務器不能利用一個緩存副本來響應這樣一個請求。

Specific end-to-end revalidation(指定的end-to-end重驗證)

請求包含一個「max-age=0」緩存控制指令,它強制每個途徑源服務器的緩存必須通過下一緩存或服務器來重驗證它所擁有的緩存項(如果有的話)。此初始請求包含一帶有客戶端當前驗證器的緩存驗證條件。

Unspecified end-to-end revalidation(未指定的end-to-end重驗證)

請求包含一個「max-age=0」緩存控制指令,它強制每個途徑源服務器的緩存必須通過下一緩存或服務器來重驗證它所擁有的緩存項(如果有的話)。此初始請求沒有包含一緩存驗證條件;沿著路徑上的第一個擁有此資源緩存項的緩存(如果有的話)在請求裡包含一帶有其緩存當前驗證器的緩存驗證條件。

max-age

當一個中間緩存被一個max-age=0的緩存控制指令強迫去重驗證它所擁有的緩存項,並且客戶端已經在請求裡包含了其本身擁有的驗證器,此驗證器可能不同於當前緩存項裡保存的驗證器。在這種情況下,緩存應該在不影響語義透明性的情況下利用任一驗證器去執行請求。

然而,驗證器的選擇可能會影響性能。最好的辦法對中間緩存來說,就是當執行請求時利用它自己的驗證器。如果服務器以304(沒有改變)回覆,那麼此緩存能返回一個它自己現在已經驗證了的副本給客戶端同時以一200(OK)狀態碼。如果服務器以一新實體和一新緩存驗證器來回覆請求,那麼此中間緩存會把返回的驗證器同客戶端請求裡的驗證器作比較,並利用強比較方法。如果客戶端的驗證器和源服務器的相等,那麼此中間緩存器只是簡單的返回304(沒有改變)響應。否則,它返回一個新的實體並且狀態碼是200的響應。

如果一個請求包含一個no-cache緩存控制指令,那麼它不應包含min-fresh,max-stale,或max-age緩存控制指令。

only-if-cache

   在一些情況下,例如糟糕的網絡連接,一客戶端可能希望一緩存只返回緩存當前保存的響應,並且不需要緩存通過源服務器對其緩存項進行重新加載或重驗證。如果這樣作,客戶端可能會包含一個only-if-cached緩存控制指令於請求裡。如果緩存接收了這樣的指令,那麼緩存應利用緩存項(但必須滿足請求的其它方面的限制)去響應,或以504(網關超時)狀態碼響應。然而,如果一組緩存作為一統一的具有良好內部連接性的系統來操作,那麼這個請求可能會轉發到緩存組的內部。

must-revalidate

   由於一個緩存可能被設置去忽略服務器指定的過期時間,並且又由於一個客戶端請求可能包含一個max-stale緩存控制指令(具有相似的作用),所以此協議同樣包含一個讓源服務器強迫緩存項被重驗證的機制。當must-revalidate緩存控制指令出現在已被緩存接收的響應裡時,那麼此緩存不能利用此緩存項,如果在它變得陳舊並且沒有通過源服務器對它進行重驗證的情況下,去響應一個後續的請求。(也就是說,緩存必須每次進行end-to-end重驗證,如果單獨地基於源服務器的Expire或max-age值,已緩存的響應是陳舊的話)

   must-revalidate緩存控制指令可以為某些協議特性提供可信賴性操作。在所有情況下,一個HTTP/1.1緩存必須遵循must-revalidate緩存控制指令;特別地,如果此緩存不能直接和源服務器通信,那麼它必須產生一個504(網關超時)響應。

   服務器應發送must-revalidate緩存控制指令,如果並且只有在服務器對實體的驗證請求失敗而導致不正確的操作時,例如一個不動聲息的未執行的金融事務。接收端不能採取任何違反此緩存控制指令的自動的行為,並且不能自動地提供一個被驗證無效的實體副本如果此副本通過源服務器重驗證失敗。

   儘管這不被推薦,用戶代理(user agent)如果在糟糕的網絡連接限制下,可能會違反此緩存控制指令,但是,如果這樣的話,它必須顯式地警告用戶這是一個未驗證的響應。警告必須在每次未驗證的訪問時被提供,而且用戶代理應需要用戶顯式地確認信息。

proxy-revalidate

   proxy-revalidate緩存控制指令和must-revalidate緩存控制指令具有相同的語義,但它不能應用於非共享(non-shared)的用戶代理緩存。它能被用於一已被授權請求的響應,去允許用戶緩存能保存或者過後能返回此響應而不需要去重驗證它(因為它已經被那個用戶授權了一次),但是服務於多個用戶的代理仍然需要每次去重驗證它(為了保證每個用戶已被授權)。注意這樣的授權響應同樣需要public緩存控制指令,這是為了允許響應能完全被緩存。

14.9.5 No-Transform緩存控制指令

no-ransform

中間緩存(代理)的實現者們已發現轉換某個實體主體的媒體類型轉是很有用的。一個非透明代理可能,例如,會在不同圖像格式之間進行轉換,這是為了節約空間或在低速的連接上減少通信流量。

然而,當這些轉換應用於某些應用的實體主體時,會引發嚴重操作問題。比如,醫學圖像應用程序,科學數據分析應用程序和利用end-to-end認證的應用程序都必須保證接收到的實體主體與原實體主體每一bit都是一致的。

所以,如果消息包括了no-ransform緩存控制指令, 那麼中間緩存或代理不能改變13.5.2節中列出的受限於no-transform緩存控制指令的頭域。這意味著緩存或代理不能改變由這些頭域指定的實體主體的任何方面(aspect),包括實體主體本身的值。

14.9.6緩存控制擴展(Cache control Extendions)

Cache-Control頭域能被擴展,可通過一個或多個cache-extension標記,每個標記可以被賦於一個值。信息擴展(這些擴展無須緩存行為的改變)可以不經改變其它緩存控制指令的語義而被添加。行為擴展是通過現有緩存控制指令的基本行為的修飾來實現的。 新 緩存控制指令與標準緩存控制指令兩者都被提供,這樣,不理解新緩存控制指令的應用程序會缺省地採用標準緩存控制指令規定的行為,而那些能理解新指令的應用 程序會將其看做是修改了標準緩存控制指令的要求。這樣,緩存控制指令的擴展可以在無須改變基本協議的情況下就能夠實現。

擴展機制依賴於一HTTP緩存,此緩存遵從所有本地HTTP版本緩存定義的緩存控制指令,遵從一定的擴展,並且會忽略所有它不能理解的緩存控制指令。

例如,考慮一個假設的名為「community」的新緩存響應控制指令,此指令被看成是對private緩存控制指令的修飾。我們定義此新緩存控制指令以表明:除共享緩存,任何被communit值命名的社區成員共享的緩存也可緩存此響應。例如,如果一個源服務器希望允許UCI社區裡的成員在他們共享緩存裡可以使用一私有響應,那麼此源服務器應該包含:

Cache-Control: private, commuity="UCI"

一個見到此頭域的緩存將會正確執行,即使此緩存不能理解這個community緩存擴展,因為緩存同樣能看到並且能理解private緩存控制指令所以這樣能導致缺省的安全行為。

不能識別的緩存控制指令必須被忽略;我們認為不能被HTTP/1.1緩存識別的任一緩存控制指令會和標準緩存控制指令(或者響應的缺省緩存能力)聯合在一起這樣緩存行為會保持最小正確性即使緩存不理解此擴展。

14.10 Connection

Connection常用頭域允許發送者指定某些專屬於某特定連接的選項,並且Connection頭域不能被代理(proxy)在以後的連接中傳送。

Connection頭域遵循如下語法:

   Connection = 「Connection」 「:」 1#(connection-token)

   connection-token = token

HTTP/1.1代理必須在轉發消息之前解析Connection頭域並且,為此頭域中每一個connection-token,從消息中刪除任何與connection-token裡同名頭域。 連接選項是由Connection頭域中出現connection-token而指明的,而不是由任何相應的附加頭域,因為附加頭域可以不被發送如果對應的那個連接沒有參數。

Connection頭域裡列出的消息頭域不得包含end-to-end頭域,例如Cache-Control頭域。

HTTP/1.1定義了「close」連接選項,這是為了讓發送者指明在完成響應後連接將被關閉。

例如

Connection:close

無論是出現在請求或響應的頭域裡都表明:在完成現有請求/響應後連接不應被視是「持續的(persistent)」(參見8.1節)。

不支持持久連接的HTTP/1.1應用程序必須在每一消息中都加上「close」連接選項。

接收到含有Connection頭域的HTTP/1.0(或更低版本)消息的系統必須要為每一個connection-token去刪除或忽略消息中與之同名的頭域。這避免以前版本的HTTP/1.1代理錯誤轉發這些頭域。

14.11 Content-Encoding

「Content-Encoding」實體頭域是對媒體類型的修飾。當此頭域出現時,其值表明對實體主體採用了何種內容編碼,從而可以知道採用何種解碼機制以獲取Content-Type頭域中指出的媒體類型。Content-Encoding頭域主要目的是可以在不丟失下層媒體類型的標識下對文檔進行壓縮。

Content-Encoding = "Content - Encoding" ":" 1#content-coding

內容編碼在3.5節裡定義。下面是一個應用的例子:

Content-Encoding:gzip

內容編碼(content-coding)是請求URI指定實體的特性。通常,實體主體以內容編碼(content-coding)的方式存儲,然而只有在此實體主體被呈現給用戶之前才能被解碼。然而,非透明代理可能會把實體主體的內容編碼(content-coding)改成接收端能理解的內容編碼(content-coding),除非「no-transform」緩存控制指令出現在消息裡。

如果實體的內容編碼不是「identity」,那麼此響應必須包含一個Content-Encoding實體頭域(見14.11節)並且列出非dentity的內容編碼。

若實體的內容編碼(content-coding)是一不被源服務器接受的請求消息,則響應必須以415狀態碼響應(不支持的媒體類型)。

若實體採用多種編碼,則內容編碼必須在Content-Encdoing頭域裡列出,而且還必須按他們被編碼的順序列出。額外的關於編碼參數的信息可以在其它實體頭域裡提供,這在此規範裡沒有定義。

14.12 Content-Language

Content-Language實體頭域描述了實體面向用戶的自然語言。請注意,這不一定等同於實體主體中用到的所有語言。

 Content-Language = 「Content-Language」 「:」 1#language-tag

語言標籤由3.10節定義。Content-Language頭域的主要目的在於讓用戶根據自己喜愛的語言來識別和區分實體。這樣,如果實體主體的內容是面向丹麥語言的用戶,那麼下面的頭域是適合的:

Content-Language: da

若未指明Content-Language頭域,那麼此內容缺省是對所有語言的用戶都支持。這既可能意味著發送者認為實體主體的內容與任意自然語言無關,也可能是發送者不知道內容該針對哪種語言。

在Content-Language頭域裡可以為內容(content)列出多種語言。例如,同時用毛裡土語和英語呈現「Treaty of Waitangi」就可以用下面表示:

Content-Language: mi,en

然而,有多種語言呈現於實體中並不代表此實體一定是為多個國家語言的用戶準備的。比如《初學拉丁文》之類的語言啟蒙教程,顯然是針對英語用戶的。這裡,合適的Content-Language頭域裡應只包括「en」。

Content-Language可應用於任意媒體類型(media type) -- 它不限於文本式的文檔。

14.13 Content-Length

Content-Length實體頭域用於指明發送給接收者實體主體(entity-bidy)的大小(以十進制的字節數表示),或是在使用HEAD方法時,指明實體主體本應在GET方法時發送實體主體的大小。

   Content-Length = 「Content-Length」 「:」 1*DIGIT

示例:

Content-Length: 3495

除非被4.4節裡規定的規則禁止,否則應用程序應該利用此頭域指明消息主體(message-body)的傳輸長度。

任何大於或等於0的Content-Length均為有效值。如果一個Content-Length沒有在消息裡給定,4.4節描述了如何判斷消息主體的長度。

請注意Content-Length頭域的含義與MIME中的關於此頭域的定義有很大的區別,MIME中,它在content-type類型為「message/external-body」的消息裡是可選的。在HTTP中,在消息被傳輸之前,如果消息的長度能被確定,那麼消息裡應該包含Content-Length頭域,除非不被4.4節裡的規則允許。

14.14 Content-Location

Content-Location實體頭域可用來為消息裡的實體提供對應資源的位置,當此實體的訪問位置獨立於請求URI時。一服務器應該為響應實體的變量(variant,譯註:見1.3節 術語)提供一個Content-Location頭域;尤其是在資源有多個對應的實體時,並且這些實體擁有各自不同的位置,並且可以通過這些位置單獨地訪問到各個實體,這時服務器應該為一個特定的變量(variant)提供一個Content-Location頭域。

   Content – Location = 「Content-Location」 「:」 (absoluteURI | relativeURI)

Content-Location的值同樣為實體定義了基URI(base URI)。

Content-Location的值並不能作為源請求URI(original requested URI)的替代物;它只能是陳述了請求時相應於特定實體的資源位置。將來的請求也許會用Content-Location裡的URI作為請求URI,如果請求期望指定那個特定實體源。

如果一個實體含有一個Content-Location頭域,並且此頭域裡的URI不同於獲得此實體的URI,那麼緩存不能認為此實體能被用於去響應基於那個Content-Location裡URI的後續請求。然而,Content-Location能被用於區分同一請求資源的多個實體,這在13.6節裡描述了。

若Content-Location擁有的是相對URI(relative URI),則此相對URI(relative URI)是相對於請求URI來解析的(Request-URI)。

PUT或POST請求中含有Content-Location頭域是沒有定義的;服務器可自由忽略它。

14.15 Content-MD5

Content-MD5實體頭域,正如RFC1864[23]裡定義的一樣,提供實體主體(entity-body)的MD5摘要(digest),為的是提供end-to-end消息完整性檢測(MIC)。(註:一MIC有利於檢測實體主體傳輸過程中的偶然性變動,但不一定能防範惡意攻擊。)

Content-MD5 = "Content-MD5" ":" md5-digest

MD5-digest=< 由RFC 1864 定義的base64的128位MD5摘要>

Content-MD5頭域可由源服務器或客戶端產生,用作實體主體的完整性檢驗。只有源服務器或客戶端可生成Content-MD5頭域;不得由代理和網關生成,否則會有悖於其作為端到端完整性檢驗的價值。任何實體主體的接收者,包括代理和網關,都可以檢查此頭域裡的摘要值與接收到的實體主體的摘要值是否相符。

MD5摘要的計算基於實體主體的內容,包括任何已應用的內容編碼(content-coding),但不包括應用於消息主體的任何傳輸編碼。若接收到的消息具有傳輸編碼,那麼傳輸編碼必須在用Content-MD5值與接收到的實體相檢測之前被解除。

這樣做的結果是:摘要的計算是基於實體主體(entity-body)的字節的,就像一條命令:如果沒有傳輸編碼被應用,它們將會被發送。

HTTP 將RFC 1864拓寬到允許對MIME復合媒體類型(如multipart/*,message/rfc822)計算摘要,但這並不改變如前所述的摘要計算方法。

有一些關於這個的後果。復合媒體類型(composite types)的實體主體可能包含許多body-part,每一個body-part都有它自己的MIME和HTTP頭域(包括Content-MD5,Content-Transfer-Encoding,和Content-Encoding頭域),如果一個body-part有一個Content-Transfer-Encoding或Content-Encoding頭域,那麼應該認為此body-part的內容已被應用此編碼,並且認為此body-part被包含於Content-MD5摘要裡,就是說在應用編碼之後。Transfer-Encoding頭域不被允許出現在body-part裡。

不可在計算或核對摘要之前就將任何其它換行轉換為CRLF:實際傳輸的文本中使用的換行必須原封不動的參與摘要計算。

註:雖然HTTP的Content-MD5的定義和RFC 1864中關於MIME實體主體的完全一樣, 但HTTP 實體主體在對Content-MD5的應用上仍然有幾處與MIME實體主體有所區別。首先,HTTP不像MIME會用Content-Transfer-Encoding頭域,而是會使用Transfer-Encoding和Content-Encoding頭域。 其次,HTTP比MIME更多地使用二進制內容類型,所以這種情況要注意用於計算摘要的字節順序是由那個類型所定義的傳輸字節順序(transmission byte order)。最後,HTTP允許文本類傳輸時採用數種換行,而不只是規範的使用CRLF的的標準形式。

14.16 Content-Range

Content-Range實體頭域與部分實體主體一起發送,用於指明部分實體主體在完整實體主體裡哪部分被採用。 範圍的單位(Range unit)在3.12節中定義。 

Content-Range = "Content-Range" ":" content-range-spec

content-range-spec = byte-content-range-spec

byte-content-range-spec = bytes-unit SP

byte-range-resp-spec "/"

( instance-length | "*" )

byte-range-resp-spec = (first-byte-pos "-" last-byte-pos)

| "*"

instance-length = 1*DIGIT

除非無法或很難判斷,此頭域應指明完整實體主體的總長度。星號「*」表示生成響應時的instance-length未知。

不像byte-ranges-specifier值(參見14.35.1節),byte-range-resp-spec必須只能指明一個範圍,並且必須包含首字節和尾字節的絕對位置。

一個帶有byte-range-resp-spec的byte-content-range-spec,如果它的last-byte-pos值小於first-byte-pos值,或它的instance-length值小於或等於它的last-byte-pos值,那麼就說明是無效的。收到無效的byte-content-range-spec將被忽略,並且任何隨其傳輸的內容都將被忽略。

響應時發送狀態碼416(請求的範圍無法滿足)的服務器應包含一個Content-Range頭域,且裡面的byte-range-resp-spec的值為「*」。instance-length指定當前選定資源的長度。狀態碼為206(部分內容)的響應不應該包含一個byte-range-resp-sepc為「*」的Content-Range頭域。

假定實體共含1234字節,byte-content-range-spec值的例子如下:

. The first 500 bytes:

bytes 0-499/1234

. The second 500 bytes:

bytes 500-999/1234

. All except for the first 500 bytes:

bytes 500-1233/1234

. The last 500 bytes:

bytes 734-1233/1234

當HTTP消息裡包含單個範圍時(比如,對單個範圍請求的響應,或對一組無縫相連的範圍請求的響應),那麼此內容必須跟隨一個Content-Range頭域,並且還應該包含一個Content-Length頭域來表明實際被傳輸字節的數量。例如,

HTTP/1.1 206 Partial content

Date: Wed, 15 Nov 1995 06:25:24 GMT

Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT

Content-Range: bytes 21010-47021/47022

Content-Length: 26012

Content-Type: image/gif

當HTTP報文包含多個範圍時(比如,對多個無重疊範圍請求的響應),它們會被當作多部分類型的消息來傳送。基於為此目的多部分媒體類型為「multipart/byteranges」,它在附錄19.2裡介紹了。見19.6.3裡關於兼容性的問題描述。

對單個範圍請求的響應不能使用multipart/byteranges媒體類型。若對多個範圍請求的響應結果為一單個範圍,那麼可以以一個multipart/byteranges媒體類型發送並且此媒體類型裡只有一個部分(part)。一個客戶端如果無法對multipart/byteranges消息解碼,那麼它不能在一請求中請求多個字節範圍。

當客戶端在一請求中申請多個字節範圍時,服務器應按他們在請求中出現順序的範圍返回他們所指定的範圍。

若服務器出於句法無效的原因忽略了byte-range-spec,它應把請求裡無效的Range頭域視為不存在。(正常情況下,這意味著返回一個包含完整實體的200響應。)

如果服務器接收到一請求,此請求包含一無法滿足的Range請求頭域(也即,所有byte-range-spec裡的first-byte-pos值大於當前選擇資源的長度),那麼它將返回一個416響應(請求的範圍無法滿足)(參見10.4.17節)。

註: 客戶端對無法滿足Range請求頭域不能指望服務器一定返回416(請求的範圍無法滿足)響應而非200(OK)的響應,因為不是所有服務器都能處理Range請求頭域。

14.17 Content-Type

Content-Type實體頭域指明發給接收者的實體主體的媒體類型,或在HEAD方法中指明若請求為GET時將發送的媒體類型。

Content-Type = "Content-Type" ":" media-type

媒體類型有3.7節定義。 此頭域的示例如下:

Content-Type: text/html; charset=ISO-8859-4

7.2.1節提供了關於確定實體媒體類型方法的進一步論述。

14.18 Date

Date常用頭域表明產生消息的日期和時間,它和RFC822中的orig-date語義一樣。此頭域值是一個在3.3.1裡描述的HTTP-date;它必須用RFC1123[8]裡的date格式發送。

      Date="Date"":"HTTP-date

舉個例子

         Date:Tue,15 Nov 1994 08:12:31GMT

源服務器在所有的響應中必須包括一個日期頭域,除了下面這些情況:

1.      如果響應的狀態代碼是100(繼續)或101(轉換協議),那麼響應根據服務器的需要可以包含一個Date頭域。

2.      如果響應狀態代碼表達了服務器的錯誤,如500(內部服務器錯誤)或503(難以獲得的服務),那麼源服務器就不適合或不能去產生一個有效的日期。

3.      如果服務器沒有時鐘,不能提供合理的當前時間的近似值,這個響應沒必要包括Date頭域,但在這種情況下必須遵照 14.18.1節中的規則。

一個收到的消息如果沒有Date頭域的話就會被接收者加上一個,如果這條消息將要被接收者緩存或者將要通過一需要日期的網關。一個沒有時鐘的HTTP實現不能在沒有重驗證響應時去緩存(保存)此響應。一個HTTP緩存,特別是一個共享緩存,應該使用一種機制,例如NTP[28],讓它的時鐘與外界可靠的時鐘保持同步。

客戶端在包括實體主體(entity-body)的消息中應該包含一個Date頭域,例如在PUT和POST請求裡,即時這樣做是可選的。一個沒有時鐘的客戶端不能在請求中發送Date頭域。

一個Date頭域中的HTTP-date不應該是一個消息產生時刻之後的日期和時間。它應該表示與消息產生時的日期和時間的最近似值,除非沒有辦法產生一個合理的精確日期和時間。理論上說,日期應該是在實體(entity)產生之前的那一刻,實際上,日期是在不影響其語義值的情況下消息產生期間的任意時刻。

14.18.1沒有時鐘的源服務器運作

一些源服務器實現可能沒有可得時鐘。一個沒有可得時鐘的源服務器不能給一個響應指定Expires或Last-Modified頭域值,除非通過一個具有可信賴時鐘的系統或用戶,把此值與此資源聯繫在一起。可以給Expires賦予一值,此值在服務器的配置時間之時或之前將被視為過去。(這允許響應提前過期而不需要為每個資源保存單獨的Expires值)。

14.19 ETag

Etag響應頭域提供了請求對應變量(variant)的當前實體標籤。與實體標籤一起使用的頭域在14.24,14.26和14.44節裡描述。實體標籤可用於比較來自同一資源的不同實體。(參見13.3.3節)

Etag =  "Etag" ":" entity-tag

例:

      ETag: "xyzzy"

      ETag: W/"xyzzy"

      ETag: ""

14.20 Expect

Expect請求頭域用於指明客戶端需要的特定服務器行為。

Expect = "Expect" ":" 1#expectation

expectation = "100-continue" | expectation-extension

expectation-extension = token [ "=" ( token | quoted-string )

*expect-params ]

expect-params = ";" token [ "=" ( token | quoted-string ) ]

一個服務器如果不能理解或遵循一個請求裡Expect頭域的任何expectation值,那麼它必須以合適的錯誤狀態碼響應。如果服務器不能滿足任何expectation值,服務器必須以417(期望失敗)狀態碼響應,或者如果服務器滿足請求時遇到其它問題,服務器必須發送4xx狀態碼。

本頭域為將來的擴展被定義成一個擴展的語法。若服務器接收到的請求含有它不支持的expectation-extension,那麼它必須以417(期望失敗)狀態響應。

expectation值的比較對於未引用標記(unquoted token)(包括「100-contine」標記)是而言是不區分大小寫的,對引用字符串(quoted-string)的expectation-extension而言是區分大小寫的。

Expect機制是hop-by-hop的:即HTTP/1.1代理(proxy)必須返回417(期望失敗)響應如果它接收了一個它不能滿足的expectation。 然而,Expect請求頭域本身是end-to-end頭域;它必須要隨請求一起轉發。

許多舊版的HTTP/1.0和HTTP/1.1應用程序並不理解Expect頭域。

參見8.2.3節中100(繼續)狀態的使用。

14.21 Expires

Expires實體頭域(entity-header)給出了在何時之後響應即被視為陳舊的。一個陳舊的緩存項不能被緩存(一個代理緩存或一個用戶代理的緩存)返回給客戶端,除非此緩存項被源服務器(或者被一個擁有實體的保鮮副本的中間緩存)驗證。見13.2節關於過期模型的進一步的討論。

Expires頭域的出現並不意味著資源在Expire指定時間時、之前或之後將會改變或不存在。

Expires頭域裡日期格式是絕對日期(absolute date)和時間,由3.3.1節中HTTP-date定義;它必須是RFC1123裡的日期格式:

Expires="Expires " ":"  HTTP-date

使用示例為:

Expires: Thu, 01 Dec 1994 16:00:00 GMT

註:若響應包含一個Cache-Control頭域,並且含有max-age緩存控制指令(參見14.9.3節),則此指令覆蓋Expires頭域。

HTTP/1.1客戶端和緩存必須把其它無效的日期格式,特別是包含「0」的日期格式看成是過去的時間(也就是說,「已經過期」)。

為了將響應標為「已經過期」,源服務器必須把Expires頭域裡的日期設為與Date頭域值相等。(參見13.2.4節裡關於過期計算的規則。)

為標記響應為「永不過期」,源服務器必須把Expires頭域裡的日期設為晚於響應發送時間一年左右。HTTP/1.1服務器不應發送超過將來一年的過期日期。

除非另外被Cache-Control頭域(見14.9節)指明,否則如果存在Expires頭域且頭域裡的日期值為某響應(可能缺省是不可緩存的)將來時間,那麼就表明此響應是可緩存的。 

14.22 From

From請求頭域,如果有的話,應該包含用戶代理當前操作用戶的email地址。這個地址應該是機器可用的地址,這被RFC 822 [9]裡的「mailbox」定義的同時也在RFC 1123 [8]裡作了修訂:

    From   = "From" ":" mailbox

例如:

    From: Email住址會使用灌水程式保護機制。你需要啟動Javascript才能觀看它

From頭域可以被用於記錄日誌和作為識別無效或不期望請求的來源。他不應該被用作訪問保護的不可靠方法。這個頭域的解釋是:此請求是代表所指定人執行,此人應該承擔這個方法執行的責任。特別的,機器人代理(robot agents)應該包含這個頭域,這樣此人應該對運行此機器人代理程序負責,並且應該能被聯繫上如果在接收端出現問題的話。

此頭域裡的網絡email地址是可以和發出請求的網絡主機(host)不同。例如,當一個請求被通過一代理(proxy)時,源作者的地址應被使用。

客戶端在沒有用戶的允許時是不應發出From頭域的,因為它可能和用戶的個人隱私或他們站點的安全策略(security policy)相衝突。強烈建議在任何一請求之前,用戶能取消,授權,和修改這個頭域的值。

14.23 Host

Host請求頭域指明了請求資源的網絡主機和端口號,這可以從用戶或相關資源給定的源URI獲得(通常是一個HTTP URL,在3.2.2節描述)。Host頭域值必須代表源服務器或網關(由那個源URL指定)的命名權限(naming authority)。這允許源服務器或網關去區分有內在歧義的URLS,例如,擁有一個IP地址對應有多個主機名服務器,它的根「/」URL。

    Host = "Host" ":" host [ ":" port ] ; 3.2.2節

一個「host」如果沒有跟隨的端口信息,那麼就採用是請求服務的的默認端口(例如,對一個HTTP URL來說,就是80端口)。例如,一個對源服務器「http://www.w3.org/pub/WWW/」的請求,可以用下面來表示:

   GET /pub/WWW/HTTP/1.1

   Host: www.w3.org

一個客戶端必須在所有HTTP/1.1請求消息裡包含一個Host頭域。如果請求URI沒有包含請求服務的網絡主機名,那麼Host頭域必須給一個空值。一個HTTP/1.1代理必須確保任何它轉發的請求消息裡必須包含一個正確的Host頭域,用於指定代理請求服務。所有基於網絡的HTTP/1.1服務器必須響應400(壞請求)狀態碼,如果請求消息裡缺少Host頭域。

見5.2和19.6.1.1節裡有針對Host頭域的其他要求。

14.24 If-Match

If-Match請求頭域是用來讓方法成為條件方法。如果一個客戶端已經從一個資源獲得一個或多個實體(entity),那麼它可以通過在If-Match頭域裡包含相應的實體標籤(entity tag)來驗證實體是否就是服務器當前實體。實體標籤(entity tag)在3.11節裡定義。這個特性使更新緩存信息只需要一個很小的事務開銷。當更新請求時,它照樣被用於防止對資源錯誤版本的不經意修改。作為一種特殊情況,「*」匹配資源的當前任何實體。

     If-Match = "If-Match" ":" ( "*" | 1#entity-tag )

如果If-Match頭域裡任何一個實體標籤假設與一個相似GET請求(沒有If-Match頭域)返迴響應裡實體的實體標籤相匹配,或者如果給出「*」並且請求資源的當前實體存在,那麼服務器可以執行請求方法就好像If-Match頭域不存在一樣。

服務器必須用強比較方法(見13.3.3)來比較If-Match裡的實體標籤(entity tag)。

如果沒有一個實體標籤匹配,或者給出了「*」但服務器上沒有當前的實體,那麼服務器不能執行此請求的方法,並且返回412響應(先決條件失敗)。這種行為是很有用的,特別是在當客戶端希望防止一更新方法(updating method)(例如PUT方法)去修改此客戶端上次獲取但現已改變的資源時,

如果請求假設在沒有If-Match頭域的情況下導致了除2XX或412以外的其他狀態碼響應,那麼If-Match頭域必須被接收端忽略。

「If-Match: *」 的含義是:此方法將被執行,如果源服務器(或緩存,很可能使用Vary機制,見14.44節)選擇的表現形式(representation)存在的話,但是如果此表現形式不存在,那麼此方法不能被執行。

如果一個請求想要更新一個資源(例如PUT)那麼它可以包含一個If-Match頭域來指明:當相應於If-Match值(一個實體標籤)的實體不再是那個資源的表現形式時,此請求方法不能被採用。這允許用戶表明:如果那個資源已經改變了而他們不知道的話,他們不希望請求成功。

例如:

       If-Match: "xyzzy"

       If-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"

       If-Match: *

既有If-Match頭域又有If-None-Match或If-Modified-Since頭域的請求的結果在本規範沒有定義。

14.25 If-Modified-Since

If-Modified-Since請求頭域被用來讓方法成為條件方法:如果請求變量(variant)自從此頭域裡指定的時間之後沒有改變,那麼服務器不應該返回實體;而是應該以304(沒有改變)狀態碼進行響應,同時返回的消息不需要消息主體(message-body)。

     If-Modified-Since = "If-Modified-Since" ":" HTTP-date

一個例子是:

     If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT

如果一個GET請求方法含有If-Modified-Since頭域但無Range頭域,那麼此方法請求的實體只有請求裡If-Modified-Since頭域中指定日期之後被改變才能被服務器返回。決定這個算法包括下列情況:

   a)如果請求假設會導致除狀態200之外的任何其它狀態碼,或者如果If-Modified-Since日期是無效的,那麼響應就和正常的GET請求的響應完全一樣。比服務器當前時間晚的日期是無效的。

   b)如果自從一個有效的If-Modified-Since日期以來,變量已經被修改了,那麼服務器應該返回一個響應同正常GET請求一樣。

  c)如果自從一個有效的If-Modified-Since日期以來,變量沒有被修改,那麼服務器應該返回一個304(沒有改變)響應。

這種特徵的目的是以一個最小的事務開銷來更新緩存信息。

     注意:Range請求頭域改變了If-Modified-Since的含義;詳細信息見14.35。

     注意:If-Modified-Since的時間是由服務器解析的,它的時鐘可能和客戶端的不同步。

     注意:當處理一個If-Modified-Since頭域的時候,一些服務器使用精確的日期比較方法,而不是小於(less-than)比較方法,來決定是否發送304(沒有改變)響應。當為緩存驗證而發送一個If-Modified-Since頭域的時候,為了得到最好的結果,客戶端被建議儘可能地去利用以前Last-Modified頭域裡被接收的日期字符串。  

     注意:如果客戶端,對同一請求,在If-Modified-Since頭域中使用任意日期代替Last-Modified頭域裡得到的日期,那麼客戶端應該知道這個日期應該能被服務器理解。由於客戶端和服務器之間時間編碼的不同,客戶端應該考慮時鍾不同步和舍入的問題。如果在客戶端第一次請求時與後來請求裡頭域If-Modified-Since指定的日期之間,文檔發生改變,這就可能會出現競爭條件,還有,如果If-Modified-Since從客戶端得到的日期沒有得到服務器時鐘的矯正,就有可能出現時鐘偏差等問題的。客戶端和服務器時間的偏差最有可能是由於網絡的延遲造成的。

既有If-Modified-Since頭域又有If-Match或If-Unmodified-Since頭域的請求的結果在本規範沒有定義。

14.26 If-None-Match

If-None-Match頭域被用於一個方法使之成為條件的。一個客戶端如果擁有一個或多個從某資源獲得的實體,那麼它能驗證在這些實體中有不存在於服務器當前實體中的實體,這通過在If-None-Match頭域裡包含這些實體相關的實體標籤(entity tag)來達到此目的。這個特性允許通過一個最小事務開銷來更新緩存信息。它同樣被用於防止一個更新方法(如,PUT)不經意的改變一個客戶端認為不存在但事實卻存在的資源。

作為特殊情況,頭域值「*」匹配資源的任何當前實體。

    If-None-Match = "If-None-Match" ":" ( "*" | 1#entity-tag )

如果If-None-Match頭域裡的任何實體標籤(entity tag)假設與一個相似的GET請求(假設沒有If-None-Match頭域)返回實體的實體標籤相匹配,或者,如果「*」被給出並且服務器關於那個資源的任何當前實體存在,那麼服務器不能執行此請求方法,除非資源的修改日期和請求裡If-Modified-Since頭域(假設有的話)裡提供的日期匹配失敗(譯註:匹配失敗說明資源改變了)。換言之,如果請求方法是GET或HEAD,那麼服務器應以304(沒有改變)來響應,並且包含匹配實體的相關緩存頭域(特別是Etag) 。對於所有其它方法,服務器必須以412(先決條件失敗)狀態碼響應。

13.3節說明了如何判斷兩實體標籤是否匹配。弱比較方法只能用於GET或HEAD請求。

如果If-None-Match頭域裡沒有實體標籤匹配,那麼服務器可以執行此請求方法就像If-None-Match頭域不存在一樣,但是必須忽略請求裡的任何If-Modified-Since頭域。也就是說,如果沒有實體標籤匹配 ,那麼服務器不能返回304(沒有改變)響應。

如果假設在沒有If-None-Match頭域存在的情況下,請求會導致除2xx及304狀態碼之外響應,那麼If-None-Match頭域必須被忽略。(見13.3.4節關於假如同時存在If-Modified-Since和If-None-Match頭域時服務器的行為的討論)

「If-None-Match: *」的意思是:如果被源服務器(或被緩存,可能利用Vary機制,見14.44節)選擇的表現形式(representation)存在的話,請求方法不能被執行,然而,如果表現形式不存在的話,請求方法是能被執行的。這個特性可以防止在多個PUT操作中的競爭。

     例:

       If-None-Match: "xyzzy"

       If-None-Match: W/"xyzzy"

       If-None-Match: "xyzzy", "r2d2xxxx", "c3piozzzz"

       If-None-Match: W/"xyzzy", W/"r2d2xxxx", W/"c3piozzzz"

       If-None-Match: *

如果一個請求含有If-None-Match頭域,還含有一個If-Match或If-Unmodified-Since頭域的話,此請求的指向結果在此規範裡沒有定義。

14.27 If-Range

如果客戶端在其緩存中有一實體的部分副本,並希望其整個緩存項是及時更新的,那麼客戶端可以在一條件GET(conditional GET)(利用了If-Unmodified-Since和If-Match頭域兩者或其中之一)請求裡利用Range請求頭域。然而,如果由於實體被改變而使條件失敗,那麼客戶端可能會發出第二次請求從而去獲得整個當前實體主體(entity-body)。

If-Range頭域允許客戶端使第二次請求短路(short-circuit)。說的通俗一點,這意味著:如果實體沒有改變,發送我想要的部分;如果實體改變了,那就把整個新實體發過來。

       If-Range = 「if-Range」 「:」( entity-tag | HTTP-date)

若客戶端沒有一實體標籤(entity tag),但有一個最後修改日期(Last-Modified date),它可以在If-Range頭域裡利用此日期。(服務器通過檢查一兩個字符即可區分合法HTTP-date與任意形式的entity-tag。)If-Range頭域只應該與一Range頭域一起使用,並且必須被忽略如果請求不包含一個Range頭域或者如果服務器不支持子範圍(sub-range)操作。

如果If-Range頭域裡給定的實體標籤匹配服務器上當前實體的實體標籤(entity tag),那麼服務器應該提供此實體的指定範圍,並利用206(部分內容)響應。如果實體標籤(entity tag)不匹配,那麼服務器應該返回整個實體,並利用200(ok)響應。

14.28 If-Unmodified-Since

If-Unmodified-Since請求頭域被用於一個方法使之成為條件方法。如果請求資源自從此頭域指定時間開始之後沒有改變,那麼服務器應該執行此請求就像If-Unmodified-Since頭域不存在一樣。

如果請求變量(variant,譯註:見術語)在此頭域指定時間後以後已經改變,那麼服務器不能執行此請求,並且必須返回412(前提條件失敗)狀態碼。

      If-Unmodified-Since = "If-Unmodified-Since" ":" HTTP-日期

   此域的應用實例:

       If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT

如果請求正常情況下(即假設在沒有If-Unmodified-Since頭域的情況下)導致任何非2xx或412狀態碼,那麼If-Unmodified-Since頭域將會忽略。

如果此頭域中指定的日期無效,那麼此頭域會被忽略。

在請求裡有If-Unmodified-Since頭域並且有If-None-Match或者If-Modified-Since頭域中的一個,這種請求的處理結果在此規範中沒有被定義。

14.29 Last-Modified

Last-Modified實體頭域(entity-header)指定了變量(variant)被源服務器所確信的最後修改的日期和時間。

       Last-Modified = 「Last-Modified」 「:」 HTTP-date

應用示例如下:

Last-Modified : Tue, 15 Nov 1994 12:45:26 GMT

此頭域的確切含義取決於源服務器的實現和源資源(original resource)的性質。 對文件而言,它可能僅僅指示文件上次修改的時間。對於包含動態部分的實體而言,它可能是組成其各個部分中最後修改時間最近的那個部分。對數據庫網關而言,它可能是記錄的最新修改時間戳。對虛擬對象來說,它可能是最後內部狀態改變的時間。

源服務器不能發送一個遲於消息產生時間的Last-Modified日期。假如資源最後修改日期可能指示將來的某個時間,那麼服務器應該用消息產生的時間替換那個日期。

源服務器獲得實體Last-Modified值應儘量靠近服務器產生響應的Date值。這允許接收者對實體修改時間作出準確的估計,特別是如果實體的改變時間接近響應產生的時間。

HTTP/1.1服務器應該儘可能地發送Last-Modified頭域。

14.30 Location

Location響應頭域被用於為了完成請求或識別一個新資源,使接收者能重定向於Location指明的URI而不是請求URI。對於201(Created)響應而言,Location是請求建立新資源的位置。對於3xx響應而言,Location應被指定服務器為自動重定向資源所喜愛的URI。Location頭域值由一個絕對URI組成。

       Location = 「Location」 「:」 absoluteURI

一個例子如下:

 Location : http://www.w3.org/pub/WWW/People.html

注: Content-Location頭域(14.14節)不同於Location頭域,Content-Location頭域指定了請求裡封裝實體的源位置。有可能一個響應即包含location也包含Content-Location頭域。在13.10節裡有關於一些方法的要求。

14.31 Max-Forwards

Max-Forwards請求頭域為TRACE(9.8節)和OPTIONS(9.2節)提供一種機制去限制轉發請求的代理或網關的數量。當客戶端嘗試去跟蹤一個好像陷入失敗或陷入循環的請求鏈時,這是非常有幫助的。

       Max-Forwards = 「Max – Forwards」 「:」 1*DIGIT

Max-Forwards值是十進制的整數,它指定了請求消息可以剩餘轉發的次數。

對於一個TRACE或OPTIONS請求,如果包含一個Max-Forwards頭域,那麼接收此請求的代理或網關必須能在轉發(forwarding)此請求之前檢查和更新Max-Forwards頭域值。如果接收的值為0,那麼接收者不能轉發此請求;而是,它必須作為最後的接收者響應。如果接收的Max-Forwards值比0大,那麼此轉發的消息必須包含一個更新了的Max-Forwards頭域,更新的值是在接收時的值上減去1。

對本規範定義的所有其它方法以及任何沒有明確作為方法定義部分的擴展方法的請求裡,Max-Forwards頭域可能會被忽略。

14.32 Pragma 

Pragma常用頭域被用於包含特定執行指令,這些指令可能被應用於請求/響應鏈中任何接收者。從協議的觀點來看,pragma指令指定的行為是可選的;然而,一些系統可能要求行為必須滿足指令的要求。

       Pragma               = 「Pragma」 「:」 1#pragma-directive

       pragma-directive =」no-cache」 | extension-pragma

       extension-pragma       =token [ 「=」 ( token | quoted-string) ]

當no-cache指令出現在請求消息中,應用程序應該轉發(forward)此請求到源服務器,即使它擁有此請求響應的緩存副本。pragma指令和no-cache緩存控制指令(見14.9)有相同的語義,並且它是為同HTTP/1.0向後兼容而被定義。當一個no-cache請求發送給一個不遵循HTTP/1.1的服務器時,客戶端應該既包含pragma指令也包含no-cache緩存控制指令。

pragma指令必須能穿過代理和網關應用程序,不管對於那些應用程序有沒有意義。因為這些指令可能對請求/響應鏈上的所有接受者有用。不可能為一個特定的接收者定義一個pragma;然而,任何對接收者不相關的pragma指令都應該被接收者忽略。

HTTP/1.1緩存應該把「Pragma:no-cache」當作好像客戶端發送了「cache-control:no-cache」。在HTTP中不會有新的pragma指令會被定義。

14.33 Proxy-Authenticate

Proxy-Authenticate響應頭域必須被包含在407響應(代理授權)裡。此頭域值由一個challenge和parameters組成,challenge指明了授權模式,而parameters應用於請求URI的代理。

       Proxy-Authenticate = "Proxy-Authenticate" ":" 1#challenge

關於HTTP訪問授權過程的描述在「HTTP Authentication:Basic and Digest Access Authentication」[43]中介紹了。不像WWW-Authenticate頭域,Proxy-Authenticate頭域只能應用於當前連接,並且不應該傳遞給下游(downstrem)客戶端。然而,一個中間代理可能需要從請求下遊客戶端而獲得它自己的證書(credentials),這在一些情況下就好像代理正在轉發Proxy-Authenticate頭域一樣。

14.34 Proxy-Authorization

Proxy-Authorization請求頭域允許客戶端讓一代理能給客戶端自己(或客戶端的用戶)授權。Proxy-Authorization頭域值由包含用戶代理(為代理和/或請求資源域)的授權信息的證書組成。

Proxy-Authorization = 「Proxy-Authorization」 「:」 credentials

HTTP訪問授權過程在「HTTP Authentication: Basic and Digest Access Authentication」[43]中描述。不像Authorization頭域,Proxy-Authorization頭域只能應用於下一個期望利用Proxy-Authenticate頭域授權的外向(outbound)代理。。

14.35 Range

14.35.1字節範圍 (Byte Ranges)

既然所有的HTTP實體都以字節序列形式的HTTP消息表示,那麼字節範圍的概念對任何HTTP實體都是有意義的.(不過並不是所有的客戶和服務器都需要支持字節範圍操作.。)

HTTP裡的字節範圍應用於實體主體的字節序列(不必和消息主體一樣)。

字節範圍操作可能會在一個實體裡指定一個字節範圍或多個字節範圍。

       ranges-specifier = byte-ranges-specifier

       byte-ranges-specifier = bytes-unit "=" byte-range-set

       byte-range-set = 1#( byte-range-spec | suffix-byte-range-spec )

       byte-range-spec = first-byte-pos "-" [last-byte-pos]

       first-byte-pos = 1*DIGIT

       last-byte-pos   = 1*DIGIT

byte-range-spec裡的first-byte-pos值給出了一個範圍裡第一個字節的偏移量.。last-byte-pos值給出了這個範圍裡最後一個字節的偏移量;也就是說,確定的字節位置必須在實體的範圍之內。字節偏移是以0為基準(譯註:0代表第一個字節,1代表第二個字節)。

如果存在last-byte-pos值,那麼它一定大於或等於那個byte-range-spec裡的first-byte-pos,否則byte-range-spec在句法上是非法的。接收者接收到包括一個或多個無效的byte-range-spec值的byte-range-set時,它必須忽略包含那個byte-range-set的頭域.。

如果last-byte-pos值不存在,或者大於或等於實體主體的當前長度,則認為last-byte-pos等於當前實體主體長度減一。

通過選擇last-byte-pos,客戶能夠限制獲得實體的字節數量而不需要知道實體的大小。

       suffix-byte-range-spec = 「-「 suffix-length

       suffix-length = 1*DIGIT

suffix-byte-range-spec用來表示實體主體的後綴,其長度由suffix-length值給出.。(也就是說,這種形式規定了實體正文的最後N個字節。)如果實體短於指定的suffix-length,則使用整個實體主體。

如果一個句法正確的byte-range-set至少包括一個這樣的byte-range-spec,它的first-byte-pos比實體主體的當前長度要小,或至少包括一個suffix-length非零的 suffix-byte-range-spec,那麼byte-range-set是可以滿足的,否則是不可滿足的。如果byte-range-set不能滿足,那麼服務器應該返回一個416響應(請求範圍不能滿足)。否則,服務器應該返回一個206響應(部分內容)

byte-ranges-specifier(字節-範圍-說明符)值的例子(假定實體主體的長度為10000):

-- 第一個500字節(字節偏移量0-499,包括0和499): bytes=0-499

-- 第二個500字節(字節偏移量500-999,包括500和999): bytes=500-999

-- 最後500字節(字節偏移量9500-9999,包括9500和9999): bytes=-500 或 bytes=9500-

-- 僅僅第一個和最後一個字節(字節0和9999): bytes=0-0,-1  

-- 關於第二個500字節(字節偏移量500-999,包括500和999)的幾種合法但不規範的敘述:

         bytes=500-600,601-999

         bytes=500-700,601-999

14.35.2範圍請求(Range Retrieval Requests)

使用條件或無條件GET方法可以請求實體的一個或多個字節範圍,而不是整個實體,這利用Range請求頭域,請求返回的結果就是Range頭域指示的請求資源實體的範圍。

     Range = "Range" ":" ranges-specifier

服務器可以忽略Range頭域。然而,.HTTP/1.1源服務器和中間緩存應該儘可能支持字節範圍,因為Range支持從部分失敗傳輸中有效地恢復,並且支持從大的實體中有效地獲取部分內容。

如果服務器支持Range頭域,並且指定的範圍或多個範圍對實體來說是適合的:

1.        如果在無條件GET請求裡出現Range頭域,那麼這將會改變沒有Range頭域時的GET請求返回的結果。換句話說,返回的狀態碼不是200(ok)而是206(部分響應)。

2.        如果在條件GET(請求裡利用了If-Modified-Since和If-None-Match中任意一個或兩者,或者利用了If-Unmodified-Since和If-Match中的任意一個或兩者)請求裡出現Range頭域,那麼這將改變返回的結果,如果GET請求假設在沒有Range頭域時被服務器成功響應並且條件為真。但如果條件為假,它不會影響304(沒有改變)響應被返回。

某些情形下,除了使用Range頭域外,可能還要同時使用If-Range頭域(見14.27節)。

如果支持範圍請求的代理接收了一個範圍請求,並轉發(forward)請求到內向(inbound)服務器,並且接收到了一個完整實體,那麼它只應該返回給客戶請求的範圍。代理將接收的整個響應存儲到它的緩存裡如果此響應滿足緩存分配策略。

14.36 Referer

Referer請求頭域允許客戶端,為了讓服務器受益,指定請求URI來源的資源URI。(Referer頭域的Referer本應該寫成Referrer,出現了筆誤)。Referer請求頭域允許服務器為了個人興趣,記錄日誌,優化緩存等來產生回退鏈接列表。它照樣允許服務器為維護而跟蹤過時或寫錯的鏈接。Referer頭域不能被發送如果請求URI從一個沒有自身URI的資源獲得,例如用戶從鍵盤輸入。

       Referer   = "Referer" ":" ( absoluteURI | relativeURI )

 例如:

       Referer: http://www.w3.org/hypertext/DataSources/Overview.html

如果Referer頭域的域值是相對URI,那麼它將被解析為相對於請求URI。URI不能包含一個片段(fragment)。見15.1.3關於安全的考慮。

14.37 Retry-After

Retry-After響應頭域能被用於一個503(服務不可得)響應,服務器用它來向請求端指明服務不可得的時長。此頭域可能被用於3xx(重定向)響應,服務器用它來(如web瀏覽器)指明用戶代理再次提交已重定向請求之前的最小等待時間。Retry-After頭域值可能是HTTP-date或者也可能是一個響應時間後的十進制整數秒。

       Retry-After = 「Retry-After」 「:」 ( HTTP-date | delta-seconds )

下面是它的兩個例子

       Retry-After: Fri,31 Dec 1999 23:59:59 GMT

       Retry-After:120

在後一例子中,延遲時間是2分鐘。

14.38 Server

Server響應頭域包含了源服務器用於處理請求的軟件信息。 此域可包含多個產品標記(3.8節),以及鑑別服務器與其他重要子產品的註釋。產品標記按它們的重要性來排列,並鑑別應用程序。

       Server = 「Server」

例:

服務器:CERN/3.0 libwww/2.17

若響應是通過代理轉發的,則代理程序不得修改Server響應頭域。作為替代,它應該包含一個Via頭域(在14.45節裡描述)。

註:揭示特定的軟件版本可能會使服務器易於受到那些針對已知安全漏洞的軟件的攻擊。 建議服務器實現者將此域作為可設置項。

14.39 TE

TE請求頭域指明客戶端可以接受哪些傳輸編碼(transfer-coding)的響應,和是否願意接受塊(chunked)傳輸編碼響應的尾部(trailer)(譯註:TE頭域和Accept-Encoding頭域與Content-Encoding頭域很相似,但TE應用於傳輸編碼(transfer coding),而Content-Encoding應用於內容編碼(content coding,見3.5節))。 TE請求頭域的值可能由包含關鍵字「trailers」 和/或用逗號分隔的擴展傳輸編碼名(擴展傳輸編碼名可能會攜帶可選的接受參數的列表)(在3.6節描述)組成。

 TE        = "TE" ":" #( t-codings )

 t-codings = "trailers" | ( transfer-extension [ accept-params ] )

如果出現關鍵字「trailers」,那麼它指明客戶端願意接受(chunked)傳輸編碼響應的尾部(trailer)。 此關鍵字為傳輸編碼(transfer-coding)值而保留,但它本身不代表一種傳輸編碼。

舉例:

       TE: deflate

       TE:

       TE: trailers, deflate;q=0.5

TE請求頭域僅適用於立即連接。所以無論何時,只要在HTTP/1.1消息中存在TE頭域,連接頭域(Connection header filed)(參見14.10節)中就必須指明。

通過TE頭域,服務器能利用下述規則來測試傳輸編碼(transfer-coding)是否是可被客戶端接受的:

1.塊(chunked)傳輸編碼總是可以接受的。如果在TE頭域裡出現關鍵字「trailers」,那麼客戶端指明它願意代表自己或任意下游(downstream)客戶端去接受塊(chunked)傳輸編碼響應裡的尾部(trailer)。這意味著,如果「trailers」給定,客戶端正在聲明所有下游(downstream)客戶端願意接收塊(chunked)傳輸編碼響應裡的尾部(trailer),或聲明它願意代表下游接收端去嘗試緩存響應。

注意:HTTP/1.1並沒有定義任何方法去限制塊傳輸編碼響應的大小,這是為了方便客戶端能緩存整個響應。

2.只要是出現在TE頭域裡的傳輸編碼都是可被請求端接受的,除非此傳輸編碼跟隨的qvalue值為0(根據3.9節中定義,qvalue為0表明是「不可接受的」(not acceptable)))

3.如果在TE頭域裡有指明多個傳輸編碼是可接受的,那麼傳輸編碼(transfer-coding)的qvalue值最大的是最容易被被接受的。塊傳輸編碼的qvalue值為1。

如果TE頭域值是空的或者TE頭域沒有出現在消息裡,那麼服務器只能認為塊(chunked)傳輸編碼的響應是請求端可以接受的。沒有傳輸編碼的消息總是可接受的。

14.40 Trailer

Trailer常用頭域值指明了以塊(chunked)傳輸編碼的消息裡尾部(trailer)用到的頭域。

                  Trailer = "Trailer" ":" 1#field-name

一個HTTP/1.1消息會包含一個Trailer頭域,如果消息利用了塊(chunked)傳輸編碼並且編碼裡的尾部(trailer)不為空。這樣做是為了使接收端知道塊(chunked)傳輸編碼響應消息尾部(trailer)有哪些頭域。

如果具有塊傳輸編碼的消息,但沒有Trailer頭域存在,則此消息的尾部(trailer)將不能包括任何頭域。3.6.1節展示了塊傳輸編碼的尾部(trailer)的利用限制。

Trailer頭域中指示的消息頭域不能包括下面的頭域:

.Transfer-Encoding

.Content-Length

.Trailer

 

14.41 Transfer-Encoding

傳輸譯碼(Transfer-Encoding)常用頭域指示了消息主體(message body)的編碼轉換,這是為了實現在接收端和發送端之間的安全數據傳輸。它不同於內容編碼(content-coding),傳輸代碼是消息的屬性,而不是實體(entity)的屬性。

       Transfer-Encoding       = "Transfer-Encoding" ":" 1#transfer-coding

 傳輸編碼(transfer-coding)在3.6節中被定義了。一個例子是:

         Transfer-Encoding: chunked

如果一個實體應用了多種傳輸編碼,傳輸編碼(transfer-coding)必須以應用的順序列出。傳輸編碼(transfer-coding)可能會提供編碼參數(譯註:看傳輸編碼的定義,3.6節),這些編碼參數額外的信息可能會被其它實體頭域(entity-header)提供,但這並沒有在規範裡定義。

 

許多老的HTTP/1.1應用程序不能理解傳輸譯碼(Transfer-Encoding)頭域。

14.42 Upgrade

Upgrade常用頭域允許客戶端指定它所支持的附加通信協議,並且可能會使用如果服務器覺得可以進行協議切換。服務器必須利用Upgrade頭域於一個101(切換協議)響應裡,用來指明哪個協議被切換了。

       Upgrade = 「Upgrade」 「:」 1#product

例如,

       Upgrade: HTTP/2.0,SHTTP/1.3, IRC/6.9, RTA/x11

Upgrade頭域的目的是為了提供一個從HTTP/1.1到其它不兼容協議的簡單遷移機制。這通過允許客戶端告訴服務器客戶端期望利用另一種協議,例如主版本號更高的最新HTTP協議,即使當前請求仍然使用HTTP/1.1。這能降低不兼容協議之間遷移的難度,只需要客戶端以一個更普遍被支持協議發起一個請求,同時告訴服務器客戶端想利用「更好的」協議如果可以的話(「更好的」由服務器決定,可能根據方法和/或請求資源的性質決定)。

Upgrade頭域只能應用於應用程序層(application –layer)協議之間的切換,應用程序層協議在傳輸層(transport-layer)連接之上。Upgrade頭域並不意味著協議一定要改變;並且服務器接受和使用是可選的。在協議改變後應用程序層(apllication-layer)的通信能力和性質,完全依賴於新協議的選擇,儘管在改變協議後的第一個動作必須是對初始HTTP請求(包含Upgrade頭域)的響應。

Upgrade頭域只能應用於立即連接(immediate connection)。因此,upgrade關鍵字必須被提供在Connection頭域裡(見14.10節),只要Upgrade頭域呈現在HTTP/1.1消息裡。

Upgrade頭域不能被用來指定切換到一個不同連接的協議。為這個目的,使用301,302,303重定向響應更合適。

這個規範定義了本協議的名字為「HTTP」,它在3.1節的HTTP版本規則中定義的超文本傳輸協議家族中被使用。任何一個標記都可被用來做協議名字,然而,只有當客戶端和服務器認為這個名字對應同一協議才有用。

14.43 User-Agent

User-Agent請求頭域包含關於發起請求的用戶代理的信息。這是為了統計,跟蹤協議違反的情況,和為了識別用戶代理從而為特定用戶代理自動定製響應。用戶代理應該包含User-Agent頭域在請求中。此頭域包含多個識別代理和子產品的產品標記(見3.8節)和解釋。通常,為了識別應用程序,產品標記按重要性排列。

      User-Agent     = "User-Agent" ":" 1*( product | comment )

例子:

       User-Agent: CERN-LineMode/2.15 libwww/2.17b3

14.44 Vary

Vary響應頭域值指定了一些請求頭域,全部去決定某緩存是否被允許去利用此響應(並且此響應仍然保鮮)去回覆後續請求而不需要重驗證(revalidation)。對於不可緩存或已陳舊的響應,Vary頭域值用於告訴用戶代理(user agent)選擇表現形式(reprentation)的標準。一個Vary頭域值是「*」意味著緩存不能根據後續請求的請求頭域來決定此響應是合適的表現形式。見13.6節關於緩存如何利用Vary頭域。

   Vary = "Vary" ":" ( "*" | 1#field-name )

一個HTTP/1.1的服務器應該包含一個Vary頭域於任何可緩存的受限於服務器驅動協商的響應裡。這樣做是允許緩存恰當去理解關於那個資源的將來請求,並通知用戶代理關於那個資源的協商出現。一個服務器可能包含一個Vary頭域於一個不可緩存的受限於服務器驅動協商的響應裡,因為這樣做可能為用戶代理提供有用的關於響應變化的維度的信息。

一個Vary頭域值由域名(filed-name)組成,響應的表現形式是基於Vary頭域裡列舉的請求頭域來選擇的。一個緩存可能會假設為將來請求進行相同的選擇,如果Vary頭域例舉了相同的域名,但必須是此響應在此期間是保鮮的。

Vary頭域裡的域名並不是侷限於本規範裡定義的標準請求頭域。域名是大小寫不敏感的。

Vary域值為「*」指明不受限於請求頭域的非特指參數(例如,客戶端的網絡地址)作用於響應表現形式中進行選擇 。「*」值不能被代理產生;它可能只能被源服務器產生。

14.45 Via

Via常用頭域必須被網關(gateways)和代理(proxies)使用,用來指明在用戶代理和服務器之間關於請求的中間協議和接收者,和在源服務器和客戶端之間關於響應的中間協議和接收者。它和RFC822[9]裡的「Received」頭域相似,並且它用於跟蹤消息的轉發,避免請求循環,和指定沿著請求/響應鏈的所有發送者的協議能力。

      Via = "Via" ":" 1#( received-protocol received-by [ comment ] )

      received-protocol = [ protocol-name "/" ] protocol-version

      protocol-name     = token

      protocol-version = token

      received-by       = ( host [ ":" port ] ) | pseudonym

      pseudonym         = token

received-protocol指出沿著請求/響應鏈每一段的服務器或客戶端所接收消息的協議版本。protocol-version被追加於Via頭域值後面,當消息被轉發時。

只要協議是HTTP,那麼protocol-name是可有可無的。received-by頭域通常是接收的轉發服務器的host(主機)和可選的port(端口)號,或接收的轉發客戶端的host(主機)和可選的port(端口)號。然而,如果真實host(主機)被看作是信息敏感的,那麼此主機可能會被別名代替。如果port(端口號)沒有被給定,那麼它可能被假設為received-protocol的缺省port(端口)號。

Via頭域裡如果有多個域值,則每個值分別代表一個已經轉發消息的代理或網關。每一個接收者必須把它的信息追加到最後,所以最後的結果是按照轉發應用程序的順序來的。

comment(註釋)可能被用於Via頭域是為了指定接收者代理或網關的軟件,這個好比User-Agent和Server頭域。然而,Via頭域裡所有的comment是可選的(譯註:可有可無的),並且可以被接收者在轉發消息之前移去。

例如,有一個請求消息來自於一個HTTP/1.0用戶代理,被發送到代號為「fred」的內部代理,此內部代理利用HTTP/1.1協議轉發此請求給一個站點為nowhere.com的公共代理,而此公共代理為了完成此請求通過把它轉發到站點為「www.ics.uci,edu」的源服務器。被「www.ics.uci.edu」站點接收後的請求這時可能有下面的Via頭域:

       Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)

被用作通向網絡防火牆的入口的代理和網關在缺省情況下不應該轉發host(主機)的名字和端口到防火牆區域裡。如果這些信息顯示地指定要被傳送,那麼就應該被傳送。如果此信息顯示地指定不能被傳送,那麼任何穿過防火牆而被接收的host(主機)應該用一個合適的別名替換。

為了隱藏組織結構的內部結構需要,一個代理(proxy)可能會在一個Via頭域中把相同received-protocal值的項合成一個項。例如,

      Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy

將被摺疊成

       Via: 1.0 ricky, 1.1 mertz, 1.0 lucy

應用程序不應該合併多個項,除非他們都在相同組織的控制下並且host(主機)已經被別名代替了。應用程序不能合並不同received-protocaol值的項。

14.46 Warning

Warning常用頭域被用於攜帶額外關於消息狀態或消息轉換的信息,而這些信息是不能在消息裡反應出來的。這些信息通常被用於去警告由於緩存操作或消息主體轉換帶來的透明性(semantic transparency)的缺失。

Warning頭域被用於響應裡,這裡有如下語法:

       Warning    = "Warning" ":" 1#warning-value

       warning-value = warn-code SP warn-agent SP warn-text

                                             [SP warn-date]

       warn-code = 3DIGIT

       warn-agent = ( host [ ":" port ] ) | pseudonym

                       ; the name or pseudonym of the server adding

                       ; the Warning header, for use in debugging

       warn-text = quoted-string

       warn-date = <"> HTTP-date <">

一個響應可能攜帶多個Warning頭域。

warn-text必須使用對於接收響應的用戶來說儘可能理解的自然語言和字符集。找到用戶自能理解的自然語言和字符集,必須基於任何可能的知識,如緩存或用戶的位置,請求裡的Accept-Language頭域,響應裡的Content-Language頭域,等等。缺省語言是英語,缺省字符集是ISO-8859-1。

如果字符集不是ISO-8859-1,那麼它必須利用RFC2047裡描述的來在warn-text裡進行編碼。

Warning頭域能被應用於任何消息,然而,一些warn-codes是特定於緩存的,並且只能被應用於響應消息。新的Warning頭域應添加到任何已存Warning頭域的後面。緩存不能刪除任何它接收到的消息裡的Warning頭域。然而,如果一緩存成功驗證一緩存項,那麼它應移除任何以前依附於那個緩存項的Warning頭域除了特定警告碼(Warning codes)的Warning頭域。然後,它必須添加這個驗證響應裡的任何Warning頭域。換句話說,Warning頭域是依附於最近相關響應的Warning頭域。

當多個Warning頭域被附加於一個響應裡,那麼用戶代理應該通知用戶儘可能多的警告,並且以它們呈現在響應裡的順序。如果用戶代理不能通知用戶所有的警告,那麼用戶代理應該按照下面的規則:

-          前面的響應裡的警告優於後面響應的警告

-          用戶偏愛的字符集的警告優於其它字符集的警告,但這除了warn-codes和warn-agents一致的情況。

產生多個Warning頭域的系統應該時刻記住利用用戶代理行為來安排警告。

關於警告的緩存行為的要求在13.1.2裡描述。

下面是當前定義的warn-codes,每一個warn-code都有一個建議性的以英語表示的warn-text,和它的意思的描述。

110 Response is stale

 無論何時當返迴響應是陳舊的時候,必須被包含。

111 Revalidation failed

   如果一個緩存因為嘗試去重驗證響應失敗而返回一個陳舊的響應(由於不能到達服務器),必須被包含。

112 Disconnected operation

   如果緩存在一段時間被有意地斷開連接,應該被包含。

113 Heuristic expiration

   如果緩存探索性地選擇了一個保鮮壽命大於24小時並且響應的年齡大於24小時時,必須被包含。

199 Miscellaneous warning

   警告文本可能包含任意信息呈現給用戶。除了呈現給用戶警告,接收警告的系統不能採取任何自動行為。

214 Transformation applied

 如果一個中間緩存或代理採用任何對響應的內容編碼(content-coding)(在Content-Encoding頭域裡指定)或媒體類型(media-type)(在Content-Type頭域裡指定)的改變變,或響應的實體主體(entity-body)的改變,那麼此響應碼必須被中間緩存或代理添加,除非此警告碼(warning code)已經在響應裡出現。

299 Miscellaneous persistent warning

 警告文本應該包含任意呈現給用戶的任意信息。接收警告的系統不能採取任何自動行為。

如果一個實現在一個消息裡發送多個版本是HTTP/1.0或更早的HTTP協議版本的Warning頭域,那麼發送者必須包含一個和響應日期(date)相等的warn-date到每一個Warning頭域值中。

如果一個實現收到一條warning-value裡包含一個warn-date的消息,並且那個warn-date不同於響應裡的Date值,那麼warning-value必須在保存,轉發,或利用消息之前從消息裡刪除。(這回防止本地緩存去緩存Warning頭域的惡果。)如果所有warning-value因為這個原因而被刪除,Warning頭域必須也要被刪除。

14.47 WWW-Authenticate

WWW-Authenticate響應頭域必須包含在401(沒有被授權)響應消息中。此域值至少應該包含一個callenge,此callenge指明授權模式(schemes)和適用於請求URI的參數。

WWW-Authenticate =「WWW-Authenticate」 「:」 1#challenge

HTTP訪問授權過程在「HTTP Authentication: Basic and Digest Access Authentication」[43]裡描述。用戶代理被建議特別小心去解析WWW-Authenticate頭域值,當此頭域值包含多個challenge,或如果多個WWW-Authenticate頭域被提供且challenge的內容能包含逗號分隔的授權參數的時候。

15.安全考慮 (Security Consideration)

這一部分是用來提醒程序開發人員,信息提供者,和用戶關於HTTP/1.1安全方面的限制。討論並不包含對被披露問題的明確的解決辦法,然而,它卻對減少安全風險提供了一些建議。

15.1 個人信息 (Personal Information)

HTTP的客戶端經常要對大量的個人信息保密(例如用戶的名字,域,郵件地址,口令,密匙等。),並且應當非常小心地防止這些信息無意識地通過HTTP協議洩露到其他的資源。我們非常強烈地建議應該給用戶提供一個方便的界面來控制這種信息的傳播,並且設計者和實現者在這方面應該特別注意。歷史告訴我們在這方面的錯誤經常引起嚴重的安全和/或者隱私問題,並導致對設計或實現者的公司產生非常不利的影響。

15.1.1服務器日誌信息的濫用 (Abuse of Server Log Information)

服務器是用來保存用來指定用戶讀模型或感興趣主題的請求的。這些信息通常顯然是需保密的,並且它的使用在某些國家被法律保護。利用HTTP協議提供數據的人們必須保證在這些數據被許可的情況下分發。

15.1.2敏感信息的傳輸 (Transfer of Sensitive Inforamtion)

就像任何數據傳輸協議一樣,HTTP不能調整傳輸數據的內容,也沒有任何經驗方法在任意給定請求的背景裡去判斷特定信息的敏感性。因此,應用程序應該儘可能為此信息提供者提供對此信息的控制。在此背景裡,有四個頭域需要提出來,這四個頭域是:Server,Via,Referer 和From。

揭露服務器特定軟件版本信息可能會使服務器的機器更容易受到通過軟件安全漏洞來進行攻擊的攻擊。實現者應該使Server頭域成為可設置的選項。

用作穿過網絡防火牆入口的代理應該特別小心防火牆後可以辨別主機信息的頭域信息被傳輸。特別是,代理應移除在防火牆之後產生的任何Via頭域。

Referer頭域允許被學習的讀模式和反向鏈接的跟蹤。雖然它非常有用,但也會被濫用如果用戶細節沒有從包含在Referer頭域裡信息裡分離開來。即使當個人信息已經被移除了,Referer頭域也可能指定私有文檔的URI(不能被公開)。

From頭域裡的信息可能會和用戶的私有興趣或他們站點的安全策略相衝突,因此From頭域不應被傳輸在用戶沒有能使此頭域的內容失效、有效和更改的情況下。用戶必須能在用戶的喜愛或應用程序的缺省設置範圍內設置此頭域的內容。

我們建議,儘管不需要,給用戶提供一個方便的開關界面來使發送From和Referer頭域有效或失效。

User-Agent(14.4節)或Server(14.38節)頭域有時候能被用來去判斷一個特定的客戶端或服務器是否存在安全漏洞。不幸的是,同樣的信息經常被用於其它有價值的目的,因為HTTP當前沒有更好的機制。

15.1.3 URI中敏感信息的編碼(Encoding Sensitive Information in URI's)

因為一個鏈接的源可能是私有信息或者可能揭露其它私有信息源,所以強烈建議用戶能選擇是否需要發送Referer頭域。例如,瀏覽器客戶端可能為了開放/匿名方式提供一個觸發開關,此開關可能使Referer頭域和From頭域信息的發送有效/無效。

如果參考頁面在一個安全的協議上傳輸,客戶端不應該包含一個Referer頭域在一個非安全HTTP請求裡。

利用HTTP協議的服務作者不應該利用基於窗體GET提交敏感數據,因為這個能引起數據在請求URI裡被編碼。許多已存在的服務,代理,和用戶代理將在對第三方可見的地方記錄請求URI。服務器能利用基於窗體POST提交來取代基於窗體GET提交。

15.1.4連接到Accept頭域的隱私問題

Accept請求頭域能揭露用戶的信息給所有被訪問的服務器。Accept-Language頭域能揭露用戶的私有信息,因為能理解特定語言的人經常被認為就是某個特定種族裡的成員。提供選項在每次請求裡去設置Accept-Language頭域的用戶代理被強烈鼓勵讓設置過程應包含一個讓用戶知道自己隱私可能被會洩漏的消息。

一種限制隱私丟失的方法可能是缺省為用戶代理去遺漏Accept-Language頭域的發送,並且詢問用戶是否給開始給服務器發送Accept-Language頭域,如果用戶代理通過查看任何由服務器產生的Vary響應頭域時發現這個發送能提高服務的質量。

每一個請求裡的用戶可配置的接受頭域(accept header fields),特別是如果這些接受頭域(accept header fileds)包含質量值,那麼應該被服務器用作相對信賴和長久的用戶標識符(user identifiers)。 這樣的用戶標識符將會允許內容提供者進行點擊跟蹤以及允許合作內容提供者匹配跨服務器點擊跟蹤或者形成單個用戶窗體提交。注意對於許多並不在代理後面的用 戶,運行用戶代理的主機的網絡地址也將作為長久用戶的標識符。在代理被用作增強隱私的環境裡,用戶代理應保守地提供接受(accept)頭域配置選項給終端用戶上。作為一種高度隱私的方式,用戶代理可能在接力的(relayed)的請求裡的過濾接受頭域。提供高度可配置性的用戶代理應警告用戶會有隱私的洩漏。

15.2 基於文件和路徑名稱的攻擊

HTTP的源服務器的實現應該限制HTTP請求返回的文檔應是服務器管理員有意圖的文檔。如果HTTP服務器要把HTTP URIs翻譯成文件系統的調用,那麼服務器必須小心去對待提供給HTTP客戶端的文件傳輸。例如,UNIX,微軟Windows,和其他操作系統都利用「..」去指示當前的父目錄。對於這樣一個系統,一HTTP服務器不允許任何這樣的構造(construct)在請求URI裡,如果這個構造能在通過HTTP服務器訪問之外能訪問這個資源。同樣的,用作對服務器內部引用的文件(如訪問控制文件,配置文件,腳本代碼)必須受到保護而不讓其被不合適的獲取,因為他們可能包含敏感的信息。經驗告訴我們一個在HTTP服務器實現裡的一個小小的錯誤會帶來安全風險。

15.3 DNS欺騙

使用HTTP的客戶端嚴重依賴於域名服務,因此這會導致基於IP和DNS名稱的不關聯的攻擊。客戶端需要小心關注IP地址/DNS名稱關聯的持久合法性。

特別是,HTTP客戶端為了確認IP地址/DNS名稱關聯性,應該依賴於客戶端自己的的名稱解析器,而不應依賴緩存以前主機(host)名稱查找(host name lookups)結果。許多平台在恰當的時候可在本地緩存主機名稱查找(host name lookups),並且他們應被配置為可這樣做。然而,只有當被名稱服務器報告的TTL(Time To Live)信息指明被緩存的信息仍然有用時,才可以緩存查找(lookups)。

如果HTTP客戶端為了提高性能去緩存主機名稱查找(host name lookups)的結果,那麼他必須觀察被DNS報告的TTL信息。

如果HTTP客戶端不能看到這條規則,那麼,當以前訪問的IP地址改變時,他們就會被欺騙。因為網絡地址的改變變得很平常,所以這種形式的攻擊在不斷增加。看到這個規則能減少潛在的安全攻擊的可能性。

此要求同樣能改進客戶端負載均衡(load-balancing)行為,因為重複的服務器能利用同一個DNS名稱,此要求能降低用戶在訪問利用策略(strategy)的站點中的體驗失敗。

15.4 Location頭域和欺騙

如果單個的服務器支持互不信任的多個組織,那麼它必須檢查響應(在據稱的組織的控制下產生)裡Location和Content-Location頭域值,以確信這些頭域不會使它們沒有權限的資源無效。

15.5 Content-Disposition的問題

RFC 1806 [35],在HTTP中經常使用的Content-Disposition(見19.5.1節)頭域就源於此文檔,有許多非常認真的安全考慮在此文檔裡說明。Content-Disposition並不是HTTP標準版本中的一部分,但自從它被廣泛應用以來,我們正在證明它對使用者的價值和風險。詳細資料見RFC 2183 [49](對RFC 1806的升級)。

15.6 授權證書和空閒客戶端

現有的HTTP客戶端和用戶代理通常會不明確地保留授權信息。HTTP/1.1並沒有為服務器提供一個方法讓服務器去指導客戶端丟棄這些緩存的證書(credentials)。這是一個重大缺陷,此缺陷需要擴展HTTP協議來解決。在某些情形下,緩存證書會幹涉應用程序的安全模型,這些情形包含但不侷限於:

Ø         這樣的客戶端。此客戶端空閒已到達一定時間,服務器可能希望再次使客戶端讓用戶出示證書。

Ø         這樣的應用程序。此應用程序包括了一個會話中斷指令(例如在一頁上有「退出」或者「提交」的按鈕),根據此指令,服務器端「知道」不需要更多理為客戶端保留證書。

這是作為當前獨立研究的。有很多解決這個問題的社區,並且我們鼓勵在屏幕保護程序、空閒超時、和其他能減輕安全問題的方法裡利用密碼保護。特別是,能緩存證書的用戶代理被鼓勵去提供一個容易的訪問控制機制,讓在用戶控制下丟棄緩存的證書。

15.7 代理和緩存 (Proxies and Caching)

本質上說,HTTP代理是中間人(men-in-the-middle),並且存在中間人攻擊(man-in-the-middle attacks)危險。系統(代理運行於其上)的缺陷能導致嚴重的安全和隱私問題。代理擁有對相關安全信息、用戶和組織的個人信息、和屬於用戶和內容提供者的專有信息的訪問權限。一個有缺陷的代理,或一個沒有考慮安全性和隱私性的代理可能會被委託用來攻擊。

代理操作者應該保護代理運行其上的系統,正如他們保護任何包含或傳輸敏感信息的系統一樣。特別是,代理上收集的日誌信息經常包含較高的個人敏感信息,和/或關於組織的信息。日誌信息應該被小心的保護,並且要合適地開發利用。(見15.1.1)節。

代理的設計者應當考慮到設計和編碼判定所涉及到的隱私和安全問題,以及他們提供給代理操作人員配置選項(尤其是缺省配置)所牽涉到的隱私和安全問題。

代理的用戶需要知道他們自比運行代理的操作員更不值得信賴;HTTP協議自身不能解決這個問題。

在合適的時候,對密碼學的正確應用,可能會保護廣泛的安全和隱私攻擊。密碼學的討論不在本協議文檔的範圍內。

15.7.1關於代理的服務攻擊的拒絕

 代理是存在的。代理很難被保護。關於此研究正在進行。

16 感謝(Acknowledgment)

這份規範大量使用了擴展BNF和David為RFC 822 [9]定義的常用結構。同樣的,它繼續使用了很多Nathaniel Borenestein和Ned Freed為MIME [7]提供的定義。我們希望在此規範裡他們的結論有助於減少過去在HTTP和互聯網郵件消息格式關係上的混淆。

HTTP協議在這幾年已經有了相當的發展。它受益於大量積極的開發人員的社區--許多人已經通過www-talk郵件列表參與進來--並且通常就是那個社區對HTTP和萬維網的成功作了重大貢獻。 Marc Andreessen, Robert Cailliau, Daniel W. Connolly, Bob Denny, John Franks, Jean-Francois Groff , Phillip M. Hallam-Baker, Hakon W. Lie, Ari Luotonen, Rob McCool, Lou Montulli, Dave Raggett, Tony Sanders, 和 Marc VanHeyningen因為他們在定義協議早期方面的貢獻應該得到特別的讚譽。

這篇文檔從所有那些參加HTTP-WG的人員的註釋中獲得了很大的益處。除了已經提到的那些人以外,下列人士對這個規範做出了貢獻:

       Gary Adams                  Ross Patterson

       Harald Tveit Alvestrand     Albert Lunde

       Keith Ball                  John C. Mallery

       Brian Behlendorf            Jean-Philippe Martin-Flatin

       Paul Burchard               Mitra

       Maurizio Codogno            David Morris

       Mike Cowlishaw              Gavin Nicol

       Roman Czyborra              Bill Perry

      Michael A. Dolan            Jeffrey Perry

       David J. Fiander            Scott Powers

       Alan Freier                 Owen Rees

       Marc Hedlund                Luigi Rizzo

       Greg Herlihy                David Robinson

       Koen Holtman                Marc Salomon

       Alex Hopmann                Rich Salz

       Bob Jernigan                Allan M. Schiffman

       Shel Kaphan                 Jim Seidman

       Rohit Khare                 Chuck Shotton

       John Klensin                Eric W. Sink

       Martijn Koster              Simon E. Spero

       Alexei Kosut                Richard N. Taylor

       David M. Kristol            Robert S. Thau

       Daniel LaLiberte            Bill (BearHeart) Weinman

       Ben Laurie                  Francois Yergeau

       Paul J. Leach               Mary Ellen Zurko

       Daniel DuBois               Josh Cohen

緩存設計的許多內容和介紹應歸於以下人士的建議和註釋:Shel Kaphan, Paul Leach, Koen Holtman, David Morris, 和 Larry Masinter。

大部分規範的範圍是基於Ari Luotonen和John Franks早期做的工作,以及從Steve Zilles另外加入的內容。

感謝Palo Alto的"cave men"。你們知道你們是誰。

Jim Gettys(這篇文檔現在的編者)特別希望感謝Roy Fielding,這篇文檔以前的編者,連同John Klensin, Jeff Mogul, Paul Leach, Dave Kristol, Koen Holtman, John Franks, Josh Cohen, Alex Hopmann, Scott Lawrence, 和Larry Masinter一起感謝他們的幫助。還要特別感謝Jeff Mogul和Scott Lawrence對「MUST/MAY/ SHOULD」使用的檢查。

Apache組,Anselm Baird-Smith,Jigsaw的作者,和Henrik Frystyk在早期實現了RFC 2068,我們希望感謝他們發現了許多這篇文檔正嘗試糾正的問題。

19 附錄

19.1 互聯網媒體類型message/http和application/http

這篇文檔除了定義HTTP/1.1協議外,同時還被作為互聯網媒體類型「message/http」和「application/http」的規範。此類型用於封裝一個HTTP請求消息或響應消息,這假設此類型遵循MIME對 所有「消息」類型關於行長度和編碼的限制。application/http類型可以用來封裝一個或者更多HTTP請求或響應信息(非混合的)的管線(pipeline)。下列是在IANA[17]註冊的。

        媒體類型名稱:    message

        媒體子類型名稱: http

       必須參數:        無

        可選參數:        版本,信息類型

        版本:封裝信息的HTTP版本號(例如,"1.1")。如果不存在,版本可以從消息的第一行確定。

        信息類型:信息類型--"請求"或者"響應"。如果不存在,類型可以從報文的第一行確定。  

        編碼考慮:只有"7bit","8bit",或者"二進制"是允許的。

        安全考慮:無

        媒體類型名稱:    application

        媒體子類型名稱: http

        必須參數:        無

        可選參數:        版本,信息類型

        版本:封裝信息的HTTP版本號(例如,"1.1")。如果不存在,版本可以從報文的第一行確定。

        信息類型:信息類型--"request"或者"response"。如果不存在,類型可以從報文的第一行確定。     

        編碼考慮:用這種類型封裝的HTTP信息是"二進制"的格式;當通過E-mail傳遞的時候一種合適的內容傳輸編碼是必須的。

        安全考慮:無         

19.2 互聯網媒體類型multipart/byteranges

當一個HTTP 206(部分內容)響應信息包含多個範圍的內容(請求響應的內容有多個非重疊的範圍),這些是作為一個多部分消息主體來被傳送的。這種用途的媒體類型被稱作"multipart/byteranges"。

multipart/byteranges媒體類型包括兩個或者更多的部分,每一個都有自己Content-type和Content-Range頭域。必需的分界參數(boundary parameter)指定分界字符串,此分界字符串用來隔離每一部分。

        媒體類型名稱:    multipart

        媒體子類型名稱: byteranges

        必須參數:        boundary

        可選參數:        無

        編碼考慮:只有"7bit","8bit",或者"二進制"是允許的。

        安全考慮:無         

例如:

HTTP/1.1 206 Partial Content

   Date: Wed, 15 Nov 1995 06:25:24 GMT

   Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT

   Content-type:multipart/byteranges;boundary=THIS_STRING_SEPARATES

   --THIS_STRING_SEPARATES

   Content-type: application/pdf

   Content-range: bytes 500-999/8000

   ...第一部分...

   --THIS_STRING_SEPARATES

   Content-type: application/pdf

   Content-range: bytes 7000-7999/8000

   ...第二部分

   --THIS_STRING_SEPARATES--

注意:

1)在實體(entity)中,在第一個分界字符串之前可以有多餘的CRLFs。

2)雖然RFC 2046 [40]允許分界字符串加引號,但是一些現有的實現會不正確的處理分界字符串

3)許多瀏覽器和服務器是按照字節範圍標準的早期草案關於使用multipart/x-byteranges媒體類型來進行編碼的的,這個草案不總是完全和HTTP/1.1中描述的版本兼容。

19.3 放鬆的應用程序 (Tolerent Applications)

雖然這篇文檔列出了HTTP/1.1消息所必須的元素,但是並不是所有的應用程序都能正確地實現。因此我們建議運行程序可以容忍偏差只要這些偏差能被無歧義的理解。

客戶端應該放鬆地解析Status-Line(狀態行);服務器也應該放鬆地解析Request-Line(請求行)。特別的,他們應該可以接受頭域之間任何數量的SP或HT字符,即使協議規定只有一個SP。

消息頭域的行終結符是CRLF。然而,當解析這樣的頭域時,我們建議應用程序能識別單一LF作為行終結符並能忽略CR。

實體主體(entity-body)的字符集應該被標記為應用於實體主體字符編碼的最小公分母,並且期望不對實體進行標記要優於對實體標記為US-ASCII或ISO-8859-1。見3.7.1和3.4.1。

對關於日期分析和編碼的要求的額外規則以及其它對日期編碼的潛在問題包含:

Ø         HTTP/1.1客戶端和緩存應該假定一個似乎是50多年以後的RFC-850日期實際上是過去的(這有助於解決"2000年"問題)。

Ø         一個HTTP/1.1的實現可以內部地表示一個比正確日期值更早的已解析後的Expires日期,但是一定不要(MUST NOT)內部地表示一個比正確日期值更遲的已解析過的Expires日期。

Ø         所有過期日期相關的計算必須用GMT時間。本地時區一定不能(MUST NOT)影響年齡或過期時間的計算。

Ø         如果一個HTTP頭域不正確的攜帶了一個非GMT時間區的日期值,那麼必須利用最保守的可能轉換把此日期值轉換成GMT時間值。

19.4 HTTP實體和RFC 2045實體之間的區別

HTTP/1.1使用了許多Internet Mail(RFC 822 [9])和Multipurpose Internet Mail Extensions(MIME [7])裡定義的結構,去允許實體以多種表現形式和擴展機制去傳輸。然而,RFC2045討論郵件,並且HTTP有許多不同於RFC2045裡描述的特徵。這些不同被小心地挑選出來優化二進制連接的性能,為了允許使用新的媒體類型有更大的靈活性,為了使時間比較變得容易,和為了承認一些早期HTTP服務器和客戶端的實效。

本附錄描述了HTTP協議不同於RFC 2045的特殊區域。在嚴格的MIME環境中的代理和網關應該意識到這些不同並且在必要的時候要提供合適地轉換。從MIME環境到HTTP的代理和網關也需要意識到這些不同因為一些轉換可能是需要的。

19.4.1 MIME版本(MIME-Version)

HTTP不是一個遵守MIME的協議。然而HTTP/1.1消息可以包含一個單獨的MIME-Version常用頭域用來指出什麼樣的MIME協議版本被用於去構造消息。利用MIME-Version頭域指明完全遵循MIME協議的消息(在RFC2045[7])。代理/網關要保證完全遵守MIME協議當把HTTP消息輸出到嚴格MIME環境的時候。

    MIME-Version   = "MIME-Version" ":" 1*DIGIT "." 1*DIGIT

在HTTP/1.1用的缺省值是MIME1.0版本。然而,HTTP/1.1消息的解析和語義是由本文檔而不是MIME規範定義的。

19.4.2轉換到規範化形式 (Conversion to Canoical Form)

RFC 2045 [7]要求一互聯網郵件實體在被傳輸之前要被轉換成一個規範化的形式,這在RFC2049[48]裡第四章裡描述的。本文檔的3.7.1節描述了當用HTTP協議傳輸時允許使用的「text」子媒體類型的形式。RFC2046要求類型為「text」的內容要用CRLF表示為換行符,以及在換行符外禁止使用CR或LF。

RFC 2046需要像在「text」類型的內容裡一樣,用CRLF表示行間隔符並禁止在行間隔符序列以外使用CR或者LF。HTTP允許CRLF,單個CR,和單個LF來表示一個換行符在一個文本內容消息中。

在可能的地方,從HTTP到MIME嚴格環境的代理或網關應該把RFC2049裡描述的text媒體類型裡所有換行符轉換成RFC2049裡CRLF的規範形式。然而,注意這可能在Content-Encoding出現的時候,以及HTTP允許利用一些沒有利用13和10代表CR和LF的字符集時候都會變得複雜。

實現者應該注意轉換將會破壞任何應用於源內容(original content)的密碼校驗和,除非源內容已經是規範化形式。因此,對任何在HTTP中使用校驗和的內容被建議要表示為規範化形式。

19.4.3日期格式的轉換 (Conversion of Date Formate)

為了簡化日期比較的過程,HTTP/1.1使用了一個限制的日期格式(3.3.1節)。其它協議的代理和網關應該保證任何消息裡出現的Date頭域應該遵循HTTP/1.1規定的格式,如果有必要需要重寫此日期。

19.4.4 Content-Encoding頭域介紹 (Introduction of Content-Encoding)

RFC 2045不包含任何等價於HTTP/1.1裡Content-Encoding頭域的概念。因為這個頭域作為媒體類型(media type)的修飾,從HTTP協議到MIME遵守協議的代理和網關在轉發消息之前必須既能改變Content-Type頭域的值,也能解碼實體主體(entity-body).。(一些為互聯網郵件類型的Content-Type的實驗性應用有使用一個媒體類型參數「; conversions=<content-coding>」去執行等價於Content-Encoding的功能。然而,此參數並不是RFC2045的部分)

19.4.5沒有Content-Transfer-Encoding頭域

HTTP不使用RFC 2045裡的Content-Transfer-Encoding(CTE)頭域。從使用MIME協議到HTTP的代理和網關在把響應消息發送給HTTP客戶端之前必須刪除任何非等價(non-identity,譯註:identity編碼,表示沒有進行任何編碼)CTE("quoted-printable"或"base64")編碼。

從HTTP到MIME協議遵循的代理和網關要確保消息在那個協議安全傳輸上是用正確的格式和正確的編碼,「安全傳輸」是通過使用的協議的限制而被定義的。這樣一個代理或網關應該用合適的Content-Transfer-Encoding頭域來標記數據如果這樣做將提高安全傳輸的可能性。

19.4.6 Transfer-Encoding頭域的介紹

HTTP/1.1介紹了Transfer-Encoding頭域(14.41節)。代理/網關在轉發經由MIME協議的消息之前必須移除任何傳輸編碼。

一個解碼"chunked"傳輸代碼(3.6節)的程序可以用代碼表示如下:

       length := 0

       read chunk-size, chunk-extension (if any) and CRLF

       while (chunk-size > 0) {

          read chunk-data and CRLF

          append chunk-data to entity-body

          length := length + chunk-size

          read chunk-size and CRLF

       }

       read entity-header

       while (entity-header not empty) {

          append entity-header to existing header fields

          read entity-header

       }

       Content-Length := length

       Remove "chunked" from Transfer-Encoding

19.4.7 MHTML和行長度限制

和MHTML實現共享代碼的HTTP實現需要瞭解MIME行長度限制。因為HTTP沒有這個限制,HTTP並不摺疊長行。用HTTP傳輸的MHTML消息遵守所有MHTML的規定,包括行長度的限制和摺疊,規範化等,因為HTTP傳輸所有消息主體(見3.7.2)並且不解析消息的內容和消息中包含任何MIME頭域。

19.5 其它特徵

RFC 1945和RFC 2068裡一些協議元素被一些已經存在的HTTP實現使用,但是這些協議元素對於大多數HTTP/1.1應用程序既不兼容也不正確。實現者被建議去瞭解這些特徵,但是不能依賴於它們的出現或不依賴於與其它HTTP/1.1應用程序的互操作性。這些特徵中的一些特徵描述了實驗性的特徵,以及還有一些特徵描述了沒有在基本HTTP/1.1規範裡被描述的實驗性部署特徵。

一些其它頭域,如Content-Dispositon和Title頭域,他們來自於SMTP和MIME協議,他們同樣經常被實現(見2076[37]).

19.5.1 Content-Disposition

Content-Disposition響應頭域被建議作為一個這樣的用途,那就是如果用戶請求要使內容被保存為一個文件,那麼此頭域被源服務器使用去建議的一個缺省的文件名。此用途來自於RFC1806[35]關於對Content-Disposition的定義。

        content-disposition = "Content-Disposition" ":"

                              disposition-type *( ";" disposition-parm )

        disposition-type = "attachment" | disp-extension-token

        disposition-parm = filename-parm | disp-extension-parm

        filename-parm = "filename" "=" quoted-string

        disp-extension-token = token

        disp-extension-parm = token "=" ( token | quoted-string )

 一個例子是:

      Content-Disposition: attachment; filename="fname.ext"

接收用戶的代理不應該(SHOULD NOT)關注任何在filename-parm參數中出現的文件路徑信息,這個參數被認為在這次僅僅是應用於HTTP實現。文件名應該(SHOULD)只被當作一個終端組件。

如果此頭域用於一個Content-Type為application/octet-stream響應裡,那麼含義就是用戶代理不應該展現響應,但是它應該直接進入一個『保存響應為…』對話框。

見15.5節關於Content-Disposition的的安全問題。

19.6 和以前版本的兼容

要求和以前的版本的兼容超出了協議規範的範圍。然而HTTP/1.1有意設計成很容易支持以前的版本。必須值得注意的是,在寫這份規範的時候,我們希望商業的HTTP/1.1服務器去:

      --接受HTTP/0.9,1.0和1.1請求的請求行(Request-Line)格式;

      --理解HTTP/0.9,1.0或1.1格式中的任何有效請求;

      --恰當地用客戶端使用的主要版本來響應。

 並且我們希望HTTP/1.1的客戶端:

      --接受HTTP/1.0和1.1響應的狀態行(Status-Line)格式;

      --懂得HTTP/0.9,1.0或1.1的格式的任何有效的響應。

對大多數HTTP/1.0的實現,每一個連接要在請求之前被客戶端建立,並且在發送響應之後要被服務器關閉。一些實現了在RFC 2068 [33]的19.7.1節描述的持久連接的Keep-Alive版本。

19.6.1對HTTP/1.0的改變

這一部分總結HTTP/1.0和HTTP/1.1之間主要的區別。

19.6.1.1 對多主機web服務器和保留IP地址簡化的改變

客戶端和服務器都支持Host請求頭域,並且如果Host請求頭域在HTTP/1.1請求裡沒有出現必須報告一錯誤,並且服務器能接受一個絕對URIs(5.1.2節),這些要求是此規範裡最重要的改變。

舊的HTTP/1.0客戶端會認為IP地址和服務器是一對一關係;沒有其它機制去區分IP地址和目標服務器。上面的改變將允許互聯網,一旦舊客戶端不再普遍使用時,可以去支持一個IP地址對應多個web站點的情況,這大大簡化了大型的web運行服務器,在那上面上分配多個IP地址給一個主機(host)會產生嚴重問題。互聯網照樣能恢復這樣一個IP地址,此IP地址作為特殊目的被分配給被用於根級(root-level)HTTP URLs的域名。給定web的增長速度和服務器的部署數量,那麼所有HTTP實現(包括對已存HTTP/1.0應用程序)應該正確地滿足下面這些需求:

    --客戶端和服務器都必須支持Host請求頭域。

    --發送HTTP/1.1請求的客戶端必須發送Host頭域。

    --如果HTTP/1.1請求不包括Host請求頭域,服務器必須報告錯誤400(Bad Request)。

    --服務器必須接受絕對URIs(absolute URIs)。

19.6.2和HTTP/1.0持久連接的兼容

一些客戶端和服務器可能希望和一些以前持久連接實現的HTTP/1.0客戶端和服務器保持兼容。HTTP/1.0持久連接需要顯式地協商,因為持久連接不是HTTP/1.0的缺省行為。關於持久連接的HTTP/1.0實驗性實現存在缺陷,並且HTTP/1.1裡的新的功能被設計成去矯正這些問題。這個缺陷是:一些已經存在的1.0客戶端可能會發送Keep-Alive頭域給不理解持久連接的代理,然後代理會把此Keep-Alive轉發給下一個內向(inbound)服務器。結果是HTTP/1.0客戶端必須禁止利用Keep-Alive,當和代理會話的時候。

然而,和代理進行會話最重要是利用持久連接,所以那個禁止很顯然不能被接受。因此,我們需要一些其它的機制去指明需要一個持久連接,並且它必須能安全地被使用甚至是當和忽略持久連接的舊代理會話。持久連接缺省是為HTTP/1.1消息的;為了聲明非持久連接(見14.10節),我們介紹一個新的關鍵字(Connection:close)。

持久連接的源HTTP/1.0的形式(Connection: Keep-Alive 和 Keep-Alive 頭域)在RFC2068裡說明

19.6.3對RFC 2068的改變

這篇規範已經被仔細的審查來糾正關鍵字的用法和消除它們的歧義;RFC 2068在遵守RFC 2119 [34] 制定的協定方面有很多問題。

澄清哪個錯誤代碼將會使入流服務器失靈(例如DNS失靈)。(10.5.5節)

CREATE有一個特點當一個資源第一次被創建的時候必須需要一個Etag。(10.2.2節)

Content-Base頭域從此規範裡刪除了:它無法廣泛的實現,並且在沒有健壯的擴展機制的情況下,沒有簡單的,安全的方式去介紹它。並且,它以一種相似的而不是相同的方式在MHTML[45]裡被使用。

略…..

廣告

无觅相关文章插件,快速提升流量

Please publish modules in offcanvas position.