Menu

超文本傳輸協議-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)。所有其他的響應必須包括消息主