天天看點

深入Jetty源碼之HTTP協定

在計算機網絡中,如果兩台機器要通信,他們首先要定義通信資料的格式,這樣在伺服器收到用戶端的請求消息時,它才能正确的解析請求的内容,然後根據請求内容處理邏輯,并将相應消息傳遞會用戶端;此時,用戶端也要根據已定義的響應資料格式解析響應消息。在浏覽器和http伺服器之間的通信資料格式使用http協定定義。

其中請求消息的格式為:

深入Jetty源碼之HTTP協定

例子:

請求消息由三部分組成:請求行、消息報頭、請求正文。

請求行格式為:請求方法、空格、url、版本号、回車、換行。請求方法集:get、post、head、put、delete、trace、connect、options。url中'?'之後的值用于表達請求參數。版本号可以是:http/1.0、http/1.1。

消息報頭格式為:報頭名字、冒号(':')、空格、報頭值、回車、換行。消息報頭用于傳遞中繼資料資訊,用于表達消息正文的類型、編碼格式、緩存等,以回車換行結束。當遇到一個空行(隻有回車換行),表示消息報頭結束。

消息正文,可以是任意定義的格式,它接在消息報頭後(空行之後)。

請求消息是否包含消息體由content-length或transfer-encoding決定,如果規範定義的請求方法不允許包含消息體,則在請求消息中不可以包含消息體。server在解析時,如果請求方法不支援消息體,則在請求消息中包含的消息體會被忽略。

請求方法:

http1.1定義的請求方法有

options:

請求查詢伺服器的性能,或查詢與資源相關的選項和需求。

該方法的response不可緩存。目前版本http不支援該請求方法包含消息實體。如果該請求包含請求消息體,http伺服器将會抛棄這些資訊。如果request-uri為*,該請求類似“ping”或“no-op”操作。

get:

請求擷取request-uri所辨別的資源。

響應消息可緩存。在get請求消息中,如果包含if-modified-since、if-unmodified-since、if-match、if-none-match、if-range字段,則該請求稱為“條件get”。

head:

請求擷取由request-uri所辨別的資源的響應消息報頭。

響應消息可緩存。

post:

在request-uri所辨別的資源後附加新的資料。

如果在http伺服器中有建立新的資源,則該方法的響應狀态碼必須是201(created),并且響應消息實體包含描述請求的狀态,以及一個location響應消息頭。該方法的響應消息不可被緩存。

put:

請求伺服器存儲一個資源,并用request-uri作為其辨別。

如果request-uri指向一個已存在的資源,那麼包含的消息實體被視為已存在資源的新版本,如果request-uri沒有對應的資源,則http伺服器可以通過該uri建立相應資源,此時http伺服器響應201(created)狀态碼。如果修改了已存在的資源,則傳回200(ok)或204(no content)。http伺服器不可以忽略content-*消息頭(如content-range),如果http伺服器不能了解該消息頭,則傳回501(not implemented)響應消息碼。

delete:

請求伺服器删除request-uri所辨別的資源。

即使該方法的傳回狀态碼表明該操作以執行成功,用戶端還是不能保證該方法需要删除的操作已經被執行了。但是http伺服器必須保證在傳回響應給用戶端的時候,http伺服器已經打算删除這個資源或把它移動到一個不可通路的位置。成功的響應碼為200(ok),并且響應消息實體中可以包含一些描述資訊;202(accept)表明這個操作還沒被完全執行;204(no content)表示這個操作已經執行完成,但是沒有響應消息實體。該方法的響應消息不可被緩存。

trace:

請求伺服器會送收到的請求資訊,主要用于測試或診斷。

該方法以200傳回辨別成功。該請求消息不可包含請求消息實體。該方法的response必須在響應消息實體中包含所有的請求消息,其相應消息的content-type值為:message/http,該response不可被緩存。

connect:

保留将來使用。

擴充的方法:

使用者自定義擴充方法。

如果server能識别某個請求方法但是不允許該請求方法,則應該傳回405(method not allowed)響應狀态。如果server無法識别某個請求方法或者目前server沒有實作這個請求方法,則應該傳回501(not implemented)狀态碼。

request-uri支援的值有:*|absoluteuri|abs_path|authority

*表示請求不應用于某個特定的資源,并且隻對于某些不需要應用于特定資源的請求方法,如:options * http/1.1

absoluteuri:當用戶端是向一個代理發送請求時需要使用absoluteuri,然後這個代理會轉發這個請求,并傳回響應。雖然按規範,http1.1用戶端隻發送absoluteuri到代理伺服器,但是為了在将來的http版本中可以允許請求都轉換成absoluteuri,所有http1.1 server必須可以解析absoluteuri風格的請求:get http://www.w3.org/pub/www/theproject.html http/1.1

authority隻在connect請求方法中使用。

abs_path:用于表示server的資源,而server本身的資訊在host消息頭中表示:

get /put/www/theproject.html http/1.1

host: www.w3.org

resource identification rules:

如果request-uri是absoluteuri,并且這個absolute的host和server的host相同,則忽略host頭。

如果request-uri不是absoluteuri,并且請求消息包含host頭,host由host消息頭決定。

如果1或2中的host不是一個合法的host,則傳回400(bad request)響應消息。

響應消息的格式定義為:

深入Jetty源碼之HTTP協定

響應消息也有三部分組成:狀态行、消息報頭、響應正文。

狀态行格式:版本号、空格、狀态、空格、狀态短語、回車、換行。版本号可以是:http/1.0、http/1.1。狀态号和狀态短語由http協定定義,狀态号有5中取值可能:

1xx:訓示資訊--表示請求已經接收,繼續處理。

2xx:成功--表示請求已經被成功接收、了解、處理。

3xx:重定向--要完成請求,必須進行更進一步操作。

4xx:用戶端錯誤--請求有文法錯誤或請求無法實作。

5xx:伺服器端錯誤--伺服器未能實作合法的請求。

常見的狀态号和狀态短語有:

200 ok --請求成功。

304 not modified --資源沒有改變。

400 bad request --用戶端請求有文法錯誤,不能被伺服器了解。

401 unauthorized --請求未經授權(和www-authenticate報頭一起使用)。

403 forbidden --伺服器收到請求,但是拒絕提供服務。

404 not found --請求資源不存在。

500 internal server error --伺服器發生不可預期的錯誤。

503 server unavailable --伺服器目前不能處理用戶端的請求,一段時間後可能恢複正常。

響應報頭和請求報頭格式一樣:報頭名、冒号(':')、空格、報頭值、回車、換行。用于記錄響應消息的中繼資料,表達響應消息的長度、編碼方式、cookiee等資訊。遇到一個空行(隻有回車換行)表示響應消息報頭結束。

響應消息正文緊随響應消息報頭(在空行後),它可以是任意的内容,由用戶端解析。

在響應消息中是否包含消息體是由請求方法和響應狀态碼決定,所有對head請求方法的響應消息不能包含任何消息體,即使在響應消息中可能會包含實體消息頭,以至于有人會認為這個響應消息包含消息體。所有1xx(informational)、204(no content)、304(not modified)響應消息不能包含消息體。所有其他的響應消息都包含消息體,即使有些時候消息體的長度是0。

協定本身,最終要的在于消息格式,http協定的請求消息和響應消息已經詳細說明了,剩下的就是一些具體細節的問題,比如uri的格式、各種消息報頭代表的含義、響應狀态号對應的含義等。因為時間有限,不做整理,是以隻是一些閱讀協定的雜記。

uri(uniform resource identifiers),又名:udi(universal document identifiers),是url(uniform resource locators)和urn(unifrom resource names)的組合。從http協定的角度,url隻是一個由字元串組成的用于名稱、位置等的辨別符。在http協定中使用url作為定位符,它的格式為:http://${host}[:${port}][${abs_path}[?${query}]]

date/time格式:因為曆史原因,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, obsolted by rfc 1036

sun nov 6 08:49:37 1994               ; ansi c's asctime() format

其中第一種格式是推薦的網絡格式,而且它是固定長度的。http1.1用戶端和伺服器端需要能接收所有以上三種日期格式,但是隻生成第一種日期格式。所有http日期、時間都必須是格林威治時間(gmt,greenwich mean time),在http中,gmt和utc(coordinated universal time)時間相同。

編碼集:同mine格式規範定義。在cotent-type頭中定義。

内容編碼:主要用于對消息實體是否壓縮、采用什麼壓縮算法的表示。在http1.1中使用accept-encoding和content-encoding頭中定義,支援的值有:gzip、compress(廢棄)、deflate(zlib格式)、identity(預設不壓縮,隻能用于accept-encoding中,不能用于content-encoding)。這些支援的格式在iana(internet assigned numbers authority)中注冊。

傳輸編碼(transfer-coding):用表示可以、需要應用到實體主體以確定通過網絡“安全傳輸”的編碼轉換。這與内容編碼不同,傳輸編碼是消息而非原始實體的屬性。所有傳輸編碼值大小寫無關,它類似于mine編碼中的content-transfer-encoding。可用的值為:chunked,identity,gzip,compress,deflat。http/1.0不支援。

媒體類型:http通過content-type和accept頭部域以提供可擴充的資料類型。值格式:

${type}/${subtype};${paramname}=${paramvalue};....

product符号:用于允許通信應用程式通過軟體名稱和版本号來辨別它自己,比如:

user-agent: cern-linemode/2.15 libwww/2.17b3

server: apache/0.84

qvalue:使用[0-1]的值來表達參數的重要性,0表示不可接受,該值的小數部分不可操作三位。

語言标簽:用于表達消息實體的自然語言,用accept-language和content-language字段表達。它的值可以是:en、en-us、en-cockney、i-cherokee、x-pig-latin等。

實體标簽:用于比較相同請求資源的兩個或多個實體的比較。如if-match、if-none-match、if-range等頭部域名。

範圍标簽:http/1.1允許用戶端值請求響應實體的某部分(範圍)作為響應消息,如range、content-range頭部域,他們的機關在http/1.1中隻支援byte。

在請求消息和響應消息中都有消息報頭,消息報頭在http1.1協定中(rfc2616)有三種類型的頭:通用頭(general header)、請求頭(request header)、響應頭(response header)、實體頭(entity header)。其格式為:header-name: header-value。其中header-name大小寫無關,以一個空行(隻包含回車和換行)結束。header-value可以以任意數量的lws開頭(一般是一個空格)。消息頭可以以至少一個sp或ht開頭的方式擴充成多行(原文:header fields can be extended over multiple lines by preceding each extra line with at least one sp or ht,感覺了解的有問題....)。相同的header-name可以重複出現。

通用消息頭:

cache-control: 

指定緩存指令。如請求相關的指令:no-cache、no-store、max-age、max-stale、min-fresh、no-transform、only-if-cached、cache-extension,響應相關的指令:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage、cache-extension。

connection:

用戶端通過發送包含close值的connection頭,表達在這次請求結束後,server可以關閉這個連接配接,此時server如果選擇發送響應後關閉連接配接,則在響應消息中需要包含值為close的connection頭。 

允許發送者指定目前connection的一些選項。http/1.1隻定義了close的值,表示響應傳回後,目前connection将會被關閉。

date: 

表示消息發送的時間,你的描述格式由rfc822定義。例如mon, 31 dec 2001 04:25:57gmt

pragma: 

用于包含實作相關的指令。如no-cache

trailer: 

表示指定的頭在chunked消息的尾部。

transfer-encoding: 

消息在傳輸時使用的編碼。如chunked。

upgrade: 

允許用戶端指定它額外支援的傳輸協定,如果伺服器發現更新的傳輸協定更合适目前請求,則它可以将目前傳輸協定轉換成更新的傳輸協定。如http/2.0, shttp/1.3, irc/6.9, rta/x11等。

via: 

用于網關或代理伺服器,以訓示用戶端和伺服器之間的中間協定和接收者。

warning: 

用于添加一些額外的狀态或轉換資訊。

請求消息頭:

請求消息頭允許用戶端傳遞一些額外關乎用戶端資訊給server,這些字段類似在方法調用中的參數。

accept: 

指定目前請求響應可以接受的媒體類型,以逗号間隔。如:“audio/*; q=0.2, audio/basic, text/html, */*”。

accept-charset: 

指定目前請求響應可以接受的字元編碼集,以逗号間隔。如“iso-8859-5, unicode-1-1; q=0.8”。

accept-encoding: 

類似accept,定義消息實體的編碼方式。如“compress, gzip, *, identity; q=0.5”等。

accept-language: 

類似accept,定義自然語言的限制。如“da, en-gb; q=0.8, en; q=0.7”等。

authorization: 

用戶端向伺服器傳遞認證資訊。

expect:

用戶端發送一個包含100-continue值的expect字段頭,以在不發送真正消息實體的情況下測試伺服器是否能接收這個消息。此時server響應417(expectation failed)或100(continue),然後用戶端決定是否要繼續發送請求消息體。

請求消息頭,用于指定用戶端對伺服器端響應行為的需求。如100-continue、102-processing等。

from: 

請求頭,指定使用者的email位址。

host: 

請求頭,指定伺服器的主機名和端口。如:www.w3.org:8080

if-match: 

請求頭,用于條件請求方法。

if-modified-since: 

請求頭,用于條件請求方法:請求變體自從指定的時間内沒有發生改變。

if-none-match: 

if-range: 

表示如果實體沒有變法,則發送給用戶端指定部分的實體。

if-unmodified-since: 

如果實體在指定時間内沒有發生變化,則直接發送響應,否則傳回412(precondition failed)的響應。

max-forwards: 

請求頭,指定最大可以被代理、網關伺服器轉發的次數。

proxy-authorization: 

請求頭,用于用戶端包含對代理伺服器的認證資訊。

range: 

訓示範圍,如bytes=0-499

referer: 

請求頭,允許用戶端指定目前uri是從哪個uri中獲得的。

te: 

請求頭,用于訓示在響應中希望接收的擴充傳輸編碼。如deflate、trailers, deflate;q=0.5等。

user-agent: 

請求頭,用于添加用戶端軟體資訊。

響應消息頭

響應消息頭允許server傳遞一些關于響應的額外資訊給用戶端。

accept-ranges: 

響應頭,允許伺服器指定它可接受的請求範圍。如“bytes”、“none”等。

age: 

響應頭,當代理伺服器用自己緩存的實體去響應請求時,該頭部表示該實體從産生到現在經過多少時間了。該數值的代為秒。

etag: 

響應消息頭,用于指定請求變體中的實體标簽的目前值。如xyzzy,w/xyzzy等。

location: 

響應頭,用于訓示接收方重定向。

proxy-authenticate: 

響應頭,在407(proxy authenticate required)響應中,它包含代理伺服器需要的驗證模式和參數。

retry-after: 

響應頭,通503(service unavailable)響應一起使用,用于指定伺服器預計不可用時間;或者3xx,用于指定用戶端在重定向之前等待的時間。

server: 

響應頭,用于添加伺服器軟體資訊。

vary:

用于訓示用于決定當響應是最新時,是否cache可以用于接下來的響應并且不用驗證的請求字段集合。

www-authenticate: 

響應頭,用于401(unauthorized)響應消息中,用于指定伺服器需要的認證模式和參數。

實體消息頭

實體消息頭屬于實體的一部分,是實體的中繼資料。

allow: 

實體頭,列出所有對目前request-uri指定資源支援的方法。

content-encoding: 

實體頭,用于指定實體内容的編碼方式。如gzip、identity等。

content-language: 

實體頭,用于定義實體内容的自然語言。如da、en、mi等。

content-length: 

實體頭,用于指定實體内容的長度。

content-location: 

實體頭,用于指定資源所在的uri。

content-md5: 

實體頭,用于表示實體内容的數字摘要。

content-range: 

實體頭,用于指定實體内容的範圍。如bytes 0-499/1234(即機關 範圍/總長度)。

content-type: 

實體頭,用于指定實體内容的媒體類型。如text/html; charset=iso-8859-4等。

expires: 

實體頭,用于響應在多少時間後在cache中失效。

last-modified: 

實體頭,用于指定伺服器認為目前變體的修改時間。

1xx: informational - request received, continuing process

這是一個臨時性的響應,在http/1.0協定中不存在,因而不可以向http/1.0的用戶端發送該狀态碼響應。用戶端必須在獲得正常響應之前能接收一個或多個1xx響應,即使它并沒有預計會收到1xx響應。該響應碼隻有狀态行和可選的響應消息頭,沒有響應消息實體。

100 - continue

用戶端應該繼續它的請求,這個暫時的響應用于通知用戶端初始的請求已經被伺服器接受,并且暫時沒有被拒絕。此時用戶端會繼續發送剩餘的請求,或者當所有請求已經發送完成時忽略該響應碼。伺服器必須在請求結束時發送一個最終的響應。

101 - switching protocols

伺服器了解并打算執行用戶端的請求,并且使用“upgrade”字段頭使用者表示伺服器會在這個連接配接中的協定更新到“upgrade”頭辨別的版本号。

2xx: success - the action was successfully received, understood, and accepted

這個系列的響應狀态碼表示用戶端的請求已經成功的接收并處理。

200 - ok

請求成功處理。

201 - created

請求成功處理并且新的資源被建立。新建立的資源可以使用uri辨別,并且該uri在響應消息的location頭中。伺服器在傳回201響應時必須保證新的資源已經被建立,如果伺服器在傳回響應時還沒來得及建立新的資源,伺服器應該傳回202(accepted)響應。

201響應還可以包含“etag”響應頭,表示實體标簽的目前值。

202 - accepted

請求被接受并處理,但是處理還未完成。這個請求不一定被成功執行,并且也不會在有結果後重新異步發送響應消息。該響應狀态主要用于一些類似batch的操作,當客戶發送請求以後,不需要繼續保持和伺服器的連接配接。傳回的消息實體需要包含請求目前的狀态以及一個指向狀态螢幕或客戶能得到結果的估計值。

203 - non-authoritative information

響應消息實體頭部傳回的元資訊不是在原始伺服器有效的集合,而是從本地或第三方中拷貝收集。目前的集合可能是原始集合的子集或超集,這個響應碼不是必須的,可以使用200(ok)替代。

204 - no content

伺服器已經成功的完成請求,該請求沒有消息實體,隻是傳回一些最新的元資訊。

205 - reset content

伺服器已經成功的完成請求,用戶端必須重置由該請求引起的文檔視圖。該響應主要用于清除用于之前輸入的表單。該響應不可以包含消息實體。

206 - partial content

伺服器已經成功完成“partial get”的請求。該響應的請求必須包含“range”頭,以及可選的“if-range”頭。響應必須包含以下頭:content-range(或值為multipart/byteranges的content-type頭)、date、etag或content-location、expires、cache-control、vary等。

3xx: redirection - further action must be taken in order to complete the request

這個系列的狀态碼表示為了完成目前請求,用戶端必須要有進一步的處理。如果接下來的請求方法是get或者head,用戶端可以自行發送接下來的請求,而不需要用于幹預。并且用戶端應該能檢測到死循環以減少網絡的堵塞。

300 - multiple choices

目前請求包含多個資源,并且在傳回消息中包含每個資源的location資訊。用戶端可以根據一定的算法自行選擇使用那個資源(沒有定義算法)。伺服器也可以指定一個推薦的選擇(在location頭中),用戶端可能會使用這個值重定向。

301 - moved permanently

請求的資源已經被永久的移動到一個新的uri上。用戶端可以自動跳轉到新的uri上。新的uri需要在響應消息的location頭中包含。

302 - found

請求的資源臨時的存在于另一個uri中。因為這個重定向還可能會改變,用戶端需要繼續使用舊的uri。臨時的uri需要包含在響應消息的location頭中。

303 - see other

請求的響應可以使用另一個uri中獲得,并且必須使用get方法擷取另一個uri上的響應。該響應碼主要用于将一個post産生的輸出重定向到一個新選擇的資源上。新的uri需要在location響應頭中給出。

304 - not modified

如果用戶端發送一個“conditional get”請求,并且該請求是被允許的,但是它所對應的文檔沒有改變,則伺服器傳回該響應。該響應不能包含消息體,但必須包含一些消息頭:date、etag、content-location、expires、cache-control、vary。

305 - use proxy

請求的資源必須通過proxy使用location響應頭中的uri通路。

306 - unused

以前版本使用,現在已經不使用,但是響應碼保留。

307 - temporary redirect

請求的資源臨時的指向另一個uri,但是由于這個重定向可能會在将來被更改,因而用戶端需要繼續使用原來的uri。臨時的uri在location響應頭中指定。

4xx: client error - the request contains bad syntax or connote be fulfilled

這個系列的響應碼用于表示用戶端錯誤請求,并且在響應實體消息中需要包含出錯原因的解釋(對head的響應除外)。

400 - bad request

文法錯誤,請求不能被伺服器了解。

401 - unauthorized

請求需要包含用于認證。響應必須包含www-authenticate頭,包含請求認證需要的資訊。用戶端可以使用包含authorization頭重新發送請求。

402 - payment required

為将來使用保留。

403 - forbidden

伺服器拒絕該請求。如果伺服器希望讓用戶端知道拒絕的原因,可以将原因放在響應消息體重,如果伺服器想暴露該原因,則可以傳回404(not found)響應。

404 - not found

伺服器沒有發現任何比對的請求uri。如果伺服器知道某些資源已經永久的被移出,并且沒有重定向位址,則需要傳回410(gone)響應。該響應也可以用于伺服器不想暴露客戶請求被拒絕的原因。

405 - method not allowed

請求方法不被對請求的資源允許。在響應消息中必須包含allow頭,指定請求資源允許的請求方法。

406 - not acceptable

請求的資源産生的響應包含了不被accept請求頭指定的特性。

407 - proxy authentication required

類似401(unauthorized),表示用戶端必須在proxy中通過認證。proxy必須傳回proxy-authenticate頭,包含請求認證需要的資訊。

408 - request time-out

伺服器已經準備好并在等待,但是用戶端在指定的時間裡沒有發送請求。

409 - conflict

因為和資源目前狀态沖突而導緻請求沒有完成。該響應碼隻有在使用者知道任何解決這個沖突,并且重新送出請求時産生。

410 - gone

請求的資源已經不在伺服器上,并且沒有更進一步的重定向位址。

411 - length required

請求消息必須包含content-length消息頭。

412 - precondition failed

伺服器對一個或多個請求消息頭的測試失敗。

413 - request entity too large

請求消息太大。如果這個條件是臨時的,則伺服器需要包含retry-after響應頭,表示這個響應時臨時的,并在指定的時間以後重試。

414 - request-uri too large

請求的uri太長。

415 - unsupported media type

請求消息格式不被支援。

416 - request range not satisfiable

在請求包含range頭,不包含if-range頭,并且請求的資源不在range指定的範圍中。響應頭中需要包含content-range表示指定資源目前的長度。

417 - expectation failed

expect請求頭指定的值不能比對伺服器的邏輯。

5xx: server error - the server failed to fulfill an apparently valid request

這個系列的響應碼用于表示伺服器存在錯誤,不能完成相應的請求。伺服器需要在響應消息體中包含出錯的描述資訊。

500 - internal server error

伺服器内部錯誤。

501 - not implemented

伺服器沒有實作目前請求。如沒有實作對應的請求方法。

502 - bad gateway

代理或網關伺服器從上遊伺服器中接收到一個不合法的響應。

503 - service unavailable

伺服器因為臨時負載過重或處于維護狀态而不能處理請求。該響應暗示伺服器目前的狀态是臨時的,如果伺服器知道什麼時候恢複可用狀态,則可以包含retry-after響應頭,如果沒有包含retry-after頭,則用戶端可以把它視為500(internal server error)來處理。

504 - gateway time-out

代理伺服器或網關伺服器在指定的時間内沒有收到上遊伺服器的響應。

505 - http version not supported

伺服器不支援或拒絕支援請求消息中指定的http版本。

參考:

rfc2616

rfc1867

http://blog.zhaojie.me/2011/03/html-form-file-uploading-programming.html

http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html

http://www.360doc.com/content/10/0930/17/3668821_57590979.shtml

繼續閱讀