API定義規(guī)范
本規(guī)范設(shè)計基于如下使用場景:
- 請求頻率不是非常高:如果產(chǎn)品的使用周期內(nèi)請求頻率非常高,建議使用雙通道的長連接,例如 socket/websocket,避免不必要的請求頭浪費資源以及重建連接帶來的性能損耗;
- 服務(wù)器不需要主動推送消息:如果需要服務(wù)器主動發(fā)起推送,也需要雙通道的長連接,例如 socket/websocket。
實踐題要:
- API 定義應(yīng)該遵循 REST 理念
- 服務(wù)端應(yīng)該為每份資源提供 Etag/Last-Modifies,針對 GET 請求校驗 ETag,分別響應(yīng)200(響應(yīng)頭帶上 ETag)或者 304
- 客戶端發(fā)起 GET 請求時,若非首次請求,要在請求中攜帶If-Modified-Since和/或If-None-Match,兩個頭的值分別是響應(yīng)中Last-Modified和ETag頭的值
- 客戶端在發(fā)起 POST 請求時應(yīng)生成 UUID 提交給服務(wù)器,若首次請求超時,執(zhí)行“重試”提交時,應(yīng)繼續(xù)使用上次生成的 UUID
- 客戶端在發(fā)起 PUT 請求時,應(yīng)使用 Conditional PUT 的機制,用 ETag 和 Last-Modified 的值確保沒有覆蓋沖突,若有沖突則服務(wù)端應(yīng)響應(yīng) 409,客戶端可根據(jù)業(yè)務(wù)需要提示用戶更新數(shù)據(jù)之后重試,或者自動更新之后重試
- 服務(wù)端在處理 POST 請求時應(yīng)該校驗 UUID 是否存在,若不存在則創(chuàng)建資源后響應(yīng)201,若存在則直接響應(yīng)201
- 客戶端的網(wǎng)絡(luò)層應(yīng)按照 HTTP 協(xié)議處理 response 中的緩存指令
下面將簡單介紹下 REST 設(shè)計理念和 HTTP 協(xié)議
REST 設(shè)計
-
協(xié)議
API與用戶的通信協(xié)議,總是使用HTTPs協(xié)議,由于 HTTP2.0對資源的壓縮及鏈路復(fù)用機制的巨大優(yōu)勢,如果可以將使用 HTTP2.0 協(xié)議版本。
如果請求頭中沒有特殊說明,所有響應(yīng)頭的 Content-Type 應(yīng)均為 application/json
-
域名
應(yīng)該盡量將API部署在專用域名之下。
-
版本
對于版本控制目前有兩種方案,一種是放在標(biāo)頭中的Accept字段里,這種思路是將 URI 所標(biāo)注的資源視作唯一的資源,將版本視作該資源的不同版本。另一種是將版本放在 URL 中,將不同版本的資源視作不同資源。具體實踐中使用哪種方式可自行決斷,但切勿兩種方式混用。
-
路徑(Endpoint)
路徑又稱"終點"(endpoint),表示API的具體網(wǎng)址。
在RESTful架構(gòu)中,每個網(wǎng)址代表一種資源(resource),所以網(wǎng)址中不能有動詞,只能有名詞,而且所用的名詞往往與數(shù)據(jù)庫的表格名對應(yīng)(非嚴(yán)格要求)。一般來說,數(shù)據(jù)庫中的表都是同種記錄的"集合"(collection),所以API中的名詞也應(yīng)該使用復(fù)數(shù)。
舉例來說,有一個API提供動物園(zoo)的信息,還包括各種動物和雇員的信息,則它的路徑應(yīng)該設(shè)計成下面這樣。
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
對“資源”的 URI 定義應(yīng)使用“路徑描述”的方式;例如,獲取某個動物園里的某個動物時應(yīng)該使用 GET 方式去如下 URI 獲取這份“資源”:
https://api.example.com/v1/zoos/ID/animals/ID
這是對路徑描述;
“查詢式”示例:https://api.example.com/v1/animal?zoo_id=ID&anima_id=ID
這是條件查詢式的表述,服務(wù)端可以在執(zhí)行效果上與路徑描述性 URI 達到一致效果,但更推薦前者。 -
HTTP動詞
客戶端和服務(wù)端之間的信息交流均被視作對資源的操作(增刪改查四個動作)
常用的HTTP動詞有下面五個(括號里是對應(yīng)的SQL命令)。
- GET(SELECT):從服務(wù)器取出資源(一項或多項)。
- 該操作是冪等的
- 服務(wù)器應(yīng)該對該請求返回 Etag/Last-Modifies
- 若非首次請求某資源,則應(yīng)該攜帶首次請求時拿到的 Etag/Last-Modifies
- 若非請求中包含 If-Modified-Since和/或If-None-Match 匹配成功,則服務(wù)器應(yīng)該返回 304 指示客戶端繼續(xù)使用之前的緩存
- 若請求未攜帶 If-Modified-Since和/或If-None-Match (緩存被清空、首次請求),則服務(wù)器應(yīng)該返回完整的資源,響應(yīng)頭中應(yīng)包含當(dāng)前該資源的 Etag和/或Last-Modifies
- POST(CREATE):在服務(wù)器新建一個資源。
- 若動作執(zhí)行成功,則服務(wù)器應(yīng)當(dāng)返回201
- 為防止重復(fù)提交的情況發(fā)生,提交請求時應(yīng)額外增加一個 UUID 參數(shù),其由客戶端生成,由服務(wù)器記錄;當(dāng)客戶端提交的數(shù)據(jù)收到 408(請求超時)再次執(zhí)行提交時,要將上次提交的 UUID 再次提交,服務(wù)器可檢索該 UUID 是否存在,若存在則直接返回201,若不存在則創(chuàng)建資源并返回201。
- PUT(UPDATE):在服務(wù)器更新資源(客戶端提供改變后的完整信息)。
- 客戶端在發(fā)起 PUT 請求時,應(yīng)使用 Conditional PUT 的機制,用 ETag 和 Last-Modified 的值確保沒有覆蓋沖突,若有沖突則服務(wù)端應(yīng)響應(yīng) 409,客戶端可根據(jù)業(yè)務(wù)需要提示用戶更新數(shù)據(jù)之后重試,或者自動更新之后重試
- PATCH(UPDATE):在服務(wù)器更新部分資源(客戶端提供需要改變的信息)。
- 同 PUT
- DELETE(DELETE):從服務(wù)器刪除資源。
還有兩個不常用的HTTP動詞。
- HEAD:獲取資源的元數(shù)據(jù)。
- OPTIONS:獲取信息,關(guān)于資源的哪些屬性是客戶端可以改變的。
例子如下
- GET /zoos:列出所有動物園
- POST /zoos:新建一個動物園
- GET /zoos/ID:獲取某個指定動物園的信息
- PUT /zoos/ID:更新某個指定動物園的信息(提供該動物園的全部信息)
- PATCH /zoos/ID:更新某個指定動物園的信息(提供該動物園的部分信息)
- DELETE /zoos/ID:刪除某個動物園
- GET /zoos/ID/animals:列出某個指定動物園的所有動物
- DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物
- GET(SELECT):從服務(wù)器取出資源(一項或多項)。
-
過濾信息(Filtering)
如果記錄數(shù)量很多,服務(wù)器不可能都將它們返回給用戶。API應(yīng)該提供參數(shù),過濾返回結(jié)果。
下面是一些常見的參數(shù)。- ?limit=10:指定返回記錄的數(shù)量
- ?offset=10:指定返回記錄的開始位置。
- ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數(shù)。
- ?sortby=name&order=asc:指定返回結(jié)果按照哪個屬性排序,以及排序順序。
- ?animal_type_id=1:指定篩選條件
參數(shù)的設(shè)計允許存在冗余,即允許API路徑和URL參數(shù)偶爾有重復(fù)。比如,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的,但推薦使用前者來定位資源;過濾條件是用來輔助定位資源的。例如當(dāng)獲取某動物時推薦使用 /animals/ID,而不是 ?animal_id=ID;但是當(dāng)不知道該動物 ID 不能通過唯一標(biāo)識精確定位時,可以使用過濾條件來輔助定位:/animals? stature=xxx&weight=xxx&......等
當(dāng)通過唯一標(biāo)識符(ID)或者過濾條件來獲取資源,如果沒有符合條件的資源時,服務(wù)器應(yīng)當(dāng)返回 404(410?416?204?custom code?具體使用哪種 code 待議;需不需要 body 待議) 給客戶端。
HTTP 協(xié)議簡介
超文本傳輸??協(xié)議(HTTP)是應(yīng)用程序級分布式,協(xié)作式,超媒體信息協(xié)議系統(tǒng)。關(guān)于 HTTP 協(xié)議請參考 W3C官方文檔
HTTP協(xié)議版本選擇
當(dāng)前 HTTP 協(xié)議已經(jīng)升級到2.0,該版本相較于上一版(1.1)有了非常大的進步,對于高并發(fā)狀態(tài)下優(yōu)勢明顯,具體資料請參考 HTTP 官網(wǎng)、 HTTP: HTTP/2、HTTP/2 簡介、HTTP/2 資料匯總 等,對于實踐來說,比較推薦直接查看HTTP/2 資料匯總,里面有較為詳盡的資料。如果條件允許,建議直接使用HTTP2.0協(xié)議。鑒于2.0和1.1的差異性,以下介紹依然基于1.1版本。
HTTP 協(xié)議頭
HTTP(HyperTextTransferProtocol)是超文本傳輸協(xié)議的縮寫,它用于傳送WWW方式的數(shù)據(jù),關(guān)于HTTP 協(xié)議的詳細內(nèi)容請參 考RFC2616。HTTP協(xié)議采用了請求/響應(yīng)模型??蛻舳讼蚍?wù)器發(fā)送一個請求,請求頭包含請求的方法、URI、協(xié)議版本、以及包含請求修飾符、客戶 信息和內(nèi)容的類似于MIME的消息結(jié)構(gòu)。服務(wù)器以一個狀態(tài)行作為響應(yīng),相應(yīng)的內(nèi)容包括消息協(xié)議的版本,成功或者錯誤編碼加上包含服務(wù)器信息、實體元信息以 及可能的實體內(nèi)容。
通常HTTP消息包括客戶端向服務(wù)器的請求消息和服務(wù)器向客戶端的響應(yīng)消息。這兩種類型的消息由一個起始行,一個或者多個標(biāo)頭,一個只是標(biāo)頭結(jié)束的空行和可 選的消息體組成。HTTP的標(biāo)頭包括通用頭,請求頭,響應(yīng)頭和實體頭四個部分。每個標(biāo)頭由一個域名,冒號(:)和域值三部分組成。域名是大小寫無關(guān)的,域 值前可以添加任何數(shù)量的空格符,標(biāo)頭可以被擴展為多行,在每行開始處,使用至少一個空格或制表符。
-
通用頭(General Header)
通用頭即可以包含在HTTP請求中,也可以包含在HTTP響應(yīng)中。通用頭的作用是描敘HTTP協(xié)議本身。比如描敘HTTP是否持續(xù)連接的Connection頭,HTTP發(fā)送日期的Date頭,描述HTTP所在的TCP連接時間的Keep-Alive頭,用于緩存控制的Cache-Control頭等。
Cache-Control標(biāo)頭
Cache -Control指定請求和響應(yīng)遵循的緩存機制。在請求消息或響應(yīng)消息中設(shè)置 Cache-Control并不會修改另一個消息處理過程中的緩存處理過程。請求時的緩存指令包括no-cache、no-store、max-age、 max-stale、min-fresh、only-if-cached,響應(yīng)消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。各個消息中的指令含義如 下:
Public指示響應(yīng)可被任何緩存區(qū)緩存。
Private指示對于單個用戶的整個或部分響應(yīng)消息,不能被共享緩存處理。這允許服務(wù)器僅僅描述當(dāng)用戶的部分響應(yīng)消息,此響應(yīng)消息對于其他用戶的請求無效。
no-cache指示請求或響應(yīng)消息不能緩存
no-store用于防止重要的信息被無意的發(fā)布。在請求消息中發(fā)送將使得請求和響應(yīng)消息都不使用緩存。
max-age指示客戶端可以接收生存期不大于指定時間(以秒為單位)的響應(yīng)。
min-fresh指示客戶端可以接收響應(yīng)時間小于當(dāng)前時間加上指定時間的響應(yīng)。
max-stale指示客戶端可以接收超出超時期間的響應(yīng)消息。如果指定max-stale消息的值,那么客戶端可以接收超出超時期指定值之內(nèi)的響應(yīng)消息。
Date標(biāo)頭
Date標(biāo)頭表示消息發(fā)送的時間,時間的描述格式由rfc822定義。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的時間表示世界標(biāo)準(zhǔn)時,換算成本地時間,需要知道用戶所在的時區(qū)。
Pragma標(biāo)頭
Pragma標(biāo)頭用來包含實現(xiàn)特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1協(xié)議中,它的含義和Cache- Control:no-cache相同。
Host標(biāo)頭
Host標(biāo)頭指定請求資源的Intenet主機和端口號,必須表示請求url的原始服務(wù)器或網(wǎng)關(guān)的位置。HTTP/1.1請求必須包含主機標(biāo)頭,否則系統(tǒng)會以400狀態(tài)碼返回。
Referer標(biāo)頭
Referer 標(biāo)頭允許客戶端指定請求uri的源資源地址,這可以允許服務(wù)器生成回退鏈表,可用來登陸、優(yōu)化cache等。他也允許廢除的或錯誤的連接由于維護的目的被 追蹤。如果請求的uri沒有自己的uri地址,Referer不能被發(fā)送。如果指定的是部分uri地址,則此地址應(yīng)該是一個相對地址。
Range標(biāo)頭
Range標(biāo)頭可以請求實體的一個或者多個子范圍。例如,
表示頭500個字節(jié):bytes=0-499
表示第二個500字節(jié):bytes=500-999
表示最后500個字節(jié):bytes=-500
表示500字節(jié)以后的范圍:bytes=500-
第一個和最后一個字節(jié):bytes=0-0,-1
同時指定幾個范圍:bytes=500-600,601-999但是服務(wù)器可以忽略此請求頭,如果無條件GET包含Range請求頭,響應(yīng)會以狀態(tài)碼206(PartialContent)返回而不是以200 (OK)。
User-Agent標(biāo)頭
User-Agent標(biāo)頭的內(nèi)容包含發(fā)出請求的用戶信息。
-
實體頭 (Entity Header)
請求消息和響應(yīng)消息都可以包含實體信息,實體信息一般由實體標(biāo)頭和實體組成。實體標(biāo)頭包含關(guān)于實體的原信息,實體頭包括Allow、Content- Base、Content-Encoding、Content-Language、 Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、 Etag、Expires、Last-Modified、extension-header。extension-header允許客戶端定義新的實體 頭,但是這些域可能無法未接受方識別。實體可以是一個經(jīng)過編碼的字節(jié)流,它的編碼方式由Content-Encoding或Content-Type定 義,它的長度由Content-Length或Content-Range定義。
常見的實體頭
Allow:服務(wù)器支持哪些請求方法(如GET、POST、PUT、DELETE等);
Content-Encoding:文檔的編碼(Encode)方法,例如:gzip,見“2.5 響應(yīng)頭”;
Content-Language:內(nèi)容的語言類型,例如:zh-cn;
Content-Length:表示內(nèi)容長度,eg:80,可參考“響應(yīng)頭”;
Content-Location:表示客戶應(yīng)當(dāng)?shù)侥睦锶ヌ崛∥臋n
Content-MD5:MD5 實體的一種MD5摘要,用作校驗和。發(fā)送方和接受方都計算MD5摘要,接受方將其計算的值與此頭標(biāo)中傳遞的值進行比較。Eg1:Content-MD5: <base64 of 128 MD5 digest>。Eg2:dfdfdfdfdfdfdff==;
Content-Range:隨部分實體一同發(fā)送;標(biāo)明被插入字節(jié)的低位與高位字節(jié)偏移,也標(biāo)明此實體的總長度。Eg1:Content-Range: 1001-2000/5000,eg2:bytes 2543-4532/7898
Content-Type:標(biāo)明發(fā)送或者接收的實體的MIME類型。EG:text/html; charset=GB2312 主類型/子類型;
Expires:資源失效時間。HTTP1.0中定義,使用的時間為服務(wù)器的絕對時間。為0證明不允許緩存;
Last-Modified:WEB 服務(wù)器認(rèn)為對象的最后修改時間,比如文件的最后修改時間,動態(tài)頁面的最后產(chǎn)生時間等等。例如:Last-Modified:Tue, 06 May 2008 02:42:43 GMT.
-
請求頭
請求頭是那些由客戶端發(fā)往服務(wù)器端以便幫助服務(wù)器端更好的滿足客戶端請求的頭。請求頭只能出現(xiàn)在HTTP請求中。比如告訴服務(wù)器只接收某種響應(yīng)內(nèi)容的Accept頭,發(fā)送Cookies的Cookie頭,顯示請求主機域的HOST頭,用于緩存的If-Match,If-Match-Since,If-None-Match頭,用于只取HTTP響應(yīng)信息中部分信息的Range頭,用于附屬HTML相關(guān)請求引用的Referee頭等。
常見請求頭如下:
Accept:瀏覽器可接受的MIME
Accept-Charset:瀏覽器可接受的字符集;
Accept-Encoding:瀏覽器能夠進行解碼的數(shù)據(jù)編碼方式,比如gzip。Servlet能夠向支持gzip的瀏覽器返回經(jīng)gzip編碼的HTML頁面。許多情形下這可以減少5到10倍的下載時間;
Accept-Language:瀏覽器所希望的語言種類,當(dāng)服務(wù)器能夠提供一種以上的語言版本時要用到;
Authorization:授權(quán)信息,通常出現(xiàn)在對服務(wù)器發(fā)送的WWW-Authenticate頭的應(yīng)答中;
Connection:表示是否需要持久連接。如果 Servlet 看到這里的值為 “Keep-Alive”,或者看到請求使用的是 HTTP 1.1(HTTP 1.1 默認(rèn)進行持久連接),它就可以利用持久連接的優(yōu)點,當(dāng)頁面包含多個元素時(例如Applet,圖片),顯著地減少下載所需要的時間。要實現(xiàn)這一點,Servlet 需要在應(yīng)答中發(fā)送一個 Content-Length 頭,最簡單的實現(xiàn)方法是:先把內(nèi)容寫入 ByteArrayOutputStream,然后在正式寫出內(nèi)容之前計算它的大?。?/p>
Content-Length:表示請求消息正文的長度;
Cookie:這是最重要的請求頭信息之一;
From:請求發(fā)送者的 email 地址,由一些特殊的 Web 客戶程序使用,瀏覽器不會用到它;
Host:初始URL中的主機和端口;
If-Modified-Since:只有當(dāng)所請求的內(nèi)容在指定的日期之后又經(jīng)過修改才響應(yīng)200(帶有完整內(nèi)容),否則返回 304“Not Modified” 應(yīng)答;
Pragma:指定“no-cache”值表示服務(wù)器必須返回一個刷新后的文檔,即使它是代理服務(wù)器而且已經(jīng)有了頁面的本地拷貝;
Referer:包含一個URL,用戶從該URL代表的頁面出發(fā)訪問當(dāng)前請求的頁面。
User-Agent:瀏覽器類型,如果Servlet返回的內(nèi)容與瀏覽器類型有關(guān)則該值非常有用;
UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE瀏覽器所發(fā)送的非標(biāo)準(zhǔn)的請求頭,表示屏幕大小、顏色深度、操作系統(tǒng)和CPU類型。
-
響應(yīng)頭
HTTP 響應(yīng)頭是那些描述 HTTP 響應(yīng)本身的頭,這里并不包含描述 HTTP 響應(yīng)中第三部分也就是 HTTP 信息的頭(這部分由entity-headers負責(zé))。比如說定時刷新的 Refresh 頭,當(dāng)遇到 503 錯誤時自動重試的 Retry-After 頭,顯示服務(wù)器信息的 Server 頭,設(shè)置 cookie 的 Set-Cookie 頭,告訴客戶端可以部分請求的 Accept-Ranges 頭等。
常見響應(yīng)頭如下:
Allow:服務(wù)器支持哪些請求方法(如GET、POST等);
Content-Encoding:文檔的編碼(Encode)方法。只有在解碼之后才可以得到Content-Type頭指定的內(nèi)容類型。利用gzip壓縮文檔能夠顯著地減少HTML文檔的下載時間。Java的GZIPOutputStream可以很方便地進行g(shù)zip壓縮,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet應(yīng)該通過查看Accept-Encoding頭(即request.getHeader("Accept-Encoding"))檢查瀏覽器是否支持gzip,為支持gzip的瀏覽器返回經(jīng)gzip壓縮的HTML頁面,為其他瀏覽器返回普通頁面;
Content-Length:表示內(nèi)容長度。只有當(dāng)瀏覽器使用持久HTTP連接時才需要這個數(shù)據(jù)。如果你想要利用持久連接的優(yōu)勢,可以把輸出文檔寫入ByteArrayOutputStram,完成后查看其大小,然后把該值放入Content-Length頭,最后通過byteArrayStream.writeTo(response.getOutputStream()發(fā)送內(nèi)容;
Content-Type: 表示后面的文檔屬于什么MIME類型。Servlet默認(rèn)為text/plain,但通常需要顯式地指定為text/html。由于經(jīng)常要設(shè)置Content-Type,因此HttpServletResponse提供了一個專用的方法setContentTyep。 可在web.xml文件中配置擴展名和MIME類型的對應(yīng)關(guān)系;
Date:Sun, 21 Sep 2014 06:18:21 GMT; 當(dāng)前的GMT時間。你可以用setDateHeader來設(shè)置這個頭以避免轉(zhuǎn)換時間格式的麻煩;
Server:服務(wù)器軟件名稱及版本。
Age:響應(yīng)給客戶端的文檔可以緩存多長時間
Vary:Accept-Encoding 告訴緩存服務(wù)器,緩存壓縮文件和非壓縮文件兩個版本,現(xiàn)在這個字段用處并不大,因為現(xiàn)在的瀏覽器都是支持壓縮的。
Expires:Sun, 1 Jan 2000 01:00:00 GMT 這個響應(yīng)頭也是跟緩存有關(guān)的,告訴客戶端在這個時間前,可以直接訪問緩存副本,很顯然這個值會存在問題,因為客戶端和服務(wù)器的時間不一定會都是相同的,如果時間不同就會導(dǎo)致問題。所以這個響應(yīng)頭是沒有Cache-Control:max-age=***這個響應(yīng)頭準(zhǔn)確的,因為max-age=date中的date是個相對時間,不僅更好理解,也更準(zhǔn)確。該字段是 在HTML 1.0 協(xié)議規(guī)定的,在1.1中已經(jīng)被功能更強大更好用的 Cache-Control 所代替;如果 Expires 和 Cache-Control 同時存在,則Cache-Control 的設(shè)置會覆蓋 Expires。
Last-Modified:文檔的最后改動時間??蛻舳丝梢酝ㄟ^If-Modified-Since請求頭提供一個日期,該請求將被視為一個GET類型的條件請求,只有改動時間遲于指定時間的文檔才會返回,否則返回一個304(Not Modified)狀態(tài)。Last-Modified也可用setDateHeader方法來設(shè)置;
Location:表示客戶應(yīng)當(dāng)?shù)侥睦锶ヌ崛∥臋n。Location 通常不是直接設(shè)置的,而是通過 HttpServletResponse的sendRedirect 方法,該方法同時設(shè)置狀態(tài)代碼為302;
Refresh:表示瀏覽器應(yīng)該在多少時間之后刷新文檔,以秒計。除了刷新當(dāng)前文檔之外,你還可以通過 setHeader("Refresh", "5; URL=http://host/path") 讓瀏覽器讀取指定的頁面。注意這種功能通常是通過設(shè)置 HTML 頁面 HEAD 區(qū)的 <META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path"> 實現(xiàn),這是因為,自動刷新或重定向?qū)τ谀切┎荒苁褂?CGI 或 Servlet 的 HTML 編寫者十分重要。但是,對于 Servlet 來說,直接設(shè)置 Refresh 頭更加方便。注意Refresh的意義是“N秒之后刷新本頁面或訪問指定頁面”,而不是“每隔N秒刷新本頁面或訪問指定頁面”。因此,連續(xù)刷新要求每次都發(fā)送一個 Refresh 頭,而發(fā)送204狀態(tài)代碼則可以阻止瀏覽器繼續(xù)刷新,不管是使用 Refresh 頭還是 <META HTTP-EQUIV="Refresh" ...>。注意 Refresh 頭不屬于 HTTP 1.1 正式規(guī)范的一部分,而是一個擴展,但 Netscape 和 IE 都支持它。
Transfer-Encoding:chunked
這個響應(yīng)頭告訴客戶端,服務(wù)器發(fā)送的資源的方式是分塊發(fā)送的。一般分塊發(fā)送的資源都是服務(wù)器動態(tài)生成的,在發(fā)送時還不知道發(fā)送資源的大小,所以采用分塊發(fā)送,每一塊都是獨立的,獨立的塊都能標(biāo)示自己的長度,最后一塊是0長度的,當(dāng)客戶端讀到這個0長度的塊時,就可以確定資源已經(jīng)傳輸完了。 -
擴展頭
在HTTP消息中,也可以使用一些在 HTTP1.1 正式規(guī)范里沒有定義的頭字段,這些頭字段統(tǒng)稱為自定義的HTTP頭或者擴展頭,他們通常被當(dāng)作是一種實體頭處理。
現(xiàn)在流行的瀏覽器實際上都支持 Cookie,Set-Cookie,Refresh和Content-Disposition等幾個常用的擴展頭字段。- Refresh:1;url=http://www.dfdf.org //過1秒跳轉(zhuǎn)到指定
- Content-Disposition:頭字段,可參考“2.5響應(yīng)頭”;
- Content-Type:WEB 服務(wù)器告訴瀏覽器自己響應(yīng)的對象的類型。
- eg1:Content-Type:application/json ;
- eg2:applicaiton/octet-stream;
- Content-Disposition:attachment; filename=aaa.zip。
HTTP緩存機制
這里有一份谷歌的緩存實踐指南
-
什么是Web緩存
WEB緩存(cache)位于Web服務(wù)器和客戶端之間。
緩存會根據(jù)請求保存輸出內(nèi)容的副本,例如html頁面,圖片,文件,當(dāng)下一個請求來到的時候:如果是相同的URL,緩存直接使用副本響應(yīng)訪問請求,而不是向源服務(wù)器再次發(fā)送請求。
HTTP協(xié)議定義了相關(guān)的消息頭來使WEB緩存盡可能好的工作。
-
緩存的優(yōu)點
- 減少相應(yīng)延遲:因為請求從緩存服務(wù)器(離客戶端更近)而不是源服務(wù)器被相應(yīng),這個過程耗時更少,讓web服務(wù)器看上去相應(yīng)更快。
- 減少網(wǎng)絡(luò)帶寬消耗:當(dāng)副本被重用時會減低客戶端的帶寬消耗;客戶可以節(jié)省帶寬費用,控制帶寬的需求的增長并更易于管理。
-
與緩存相關(guān)的HTTP擴展消息頭
- Expires:指示響應(yīng)內(nèi)容過期的時間,格林威治時間GMT
- Cache-Control:更細致的控制緩存的內(nèi)容
- Last-Modified:響應(yīng)中資源最后一次修改的時間
- ETag:響應(yīng)中資源的校驗值,在服務(wù)器上某個時段是唯一標(biāo)識的。
- Date:服務(wù)器的時間
- If-Modified-Since:客戶端存取的該資源最后一次修改的時間,同Last-Modified。
- If-None-Match:客戶端存取的該資源的檢驗值,同ETag。
-
客戶端緩存生效的常見流程
服務(wù)器收到請求時,會在 “200 OK” 中回送該資源的Last-Modified和ETag頭,客戶端將該資源保存在cache中,并記錄這兩個屬性。當(dāng)客戶端需要發(fā)送相同的請求時,會在請求中攜帶If-Modified-Since和If-None-Match兩個頭。兩個頭的值分別是響應(yīng)中Last-Modified和ETag頭的值。服務(wù)器通過這兩個頭判斷本地資源未發(fā)生變化,客戶端不需要重新下載,返回304響應(yīng)。常見流程如下圖所示:
-
Web緩存機制
HTTP/1.1中緩存的目的是為了在很多情況下減少發(fā)送請求,同時在許多情況下可以不需要發(fā)送完整響應(yīng)。對于客戶端,可以減少不必要的請求數(shù)量,HTTP利用一個“過期(expiration)”機制達到此目的。對于服務(wù)端,可以減少響應(yīng)帶寬,HTTP用“驗證(validation)”機制達到此目的。
HTTP定義了3種緩存機制:
1)Freshness:允許一個回應(yīng)消息可以在源服務(wù)器不被重新檢查,并且可以由服務(wù)器和客戶端來控制。例如,Expires回應(yīng)頭給了一個文檔不可用的時間。Cache-Control中的max-age標(biāo)識指明了緩存的最長時間;
2)Validation:用來檢查以一個緩存的回應(yīng)是否仍然可用。例如,如果一個回應(yīng)有一個Last-Modified回應(yīng)頭,緩存能夠使用If-Modified-Since來判斷是否已改變,以便判斷根據(jù)情況發(fā)送請求;
3)Invalidation: 在另一個請求通過緩存的時候,常常有一個副作用。例如,如果一個URL關(guān)聯(lián)到一個緩存回應(yīng),但是其后跟著POST、PUT和DELETE的請求的話,緩存就會過期。
-
斷點續(xù)傳和多線程下載的實現(xiàn)原理
- HTTP協(xié)議的GET方法,支持只請求某個資源的某一部分;
- 206 Partial Content 部分內(nèi)容響應(yīng);
- Range 請求的資源范圍;
- Content-Range 響應(yīng)的資源范圍;
- 在連接斷開重連時,客戶端只請求該資源未下載的部分,而不是重新請求整個資源,來實現(xiàn)斷點續(xù)傳。
分塊請求資源實例:
Eg1:Range: bytes=306302- :請求這個資源從306302個字節(jié)到末尾的部分;
Eg2:Content-Range: bytes 306302-604047/604048:響應(yīng)中指示攜帶的是該資源的第306302-604047的字節(jié),該資源共604048個字節(jié);
客戶端通過并發(fā)的請求相同資源的不同片段,來實現(xiàn)對某個資源的并發(fā)分塊下載。從而達到快速下載的目的。目前流行的FlashGet和迅雷基本都是這個原理。
多線程下載的原理:
- 下載工具開啟多個發(fā)出HTTP請求的線程;
- 每個http請求只請求資源文件的一部分:Content-Range: bytes 20000-40000/47000;
- 合并每個線程下載的文件。
HTTP響應(yīng)
響應(yīng)
-
狀態(tài)碼定義(官方文檔)
每個狀態(tài)代碼如下所述,包括可以遵循哪些方法以及響應(yīng)中需要的任何元信息的描述。
信息1xx
這類狀態(tài)代碼指明了一個備用的響應(yīng),包含一個Status-Line和可選的標(biāo)頭,并且一一個空行結(jié)束(譯注:空行就是CRLF)。沒有必須的標(biāo)頭對這類狀態(tài)碼。因為HTTP/1.0沒有定義任何1xx狀態(tài)碼,所以服務(wù)器不能發(fā)送一個1xx響應(yīng)給一個HTTP/1.1客戶端,除了實驗性的目的。
客戶端必須能準(zhǔn)備去接受一個或多個1xx狀態(tài)響應(yīng)優(yōu)先于一個常規(guī)響應(yīng),即使客戶端不期望100(繼續(xù))狀態(tài)響應(yīng)。不被客戶端期望的1xx狀態(tài)響應(yīng)可能會被用戶代理忽略。
代理服務(wù)器必須能轉(zhuǎn)發(fā)1xx響應(yīng),除非代理服務(wù)器和它的客戶端的連接關(guān)閉了,或者除非代理服務(wù)器自己響應(yīng)請求并產(chǎn)生1xx響應(yīng)。(例如:如果代理服務(wù)器添加了”Expect:100-continue”標(biāo)頭當(dāng)轉(zhuǎn)發(fā)請求時,那么它不必轉(zhuǎn)發(fā)相應(yīng)的100(繼續(xù))響應(yīng)。)2.1.1 100 繼續(xù) (Continue)
客戶應(yīng)該繼續(xù)請求。該臨時響應(yīng)用于通知客戶端請求的初始部分已被接收,并且尚未被服務(wù)器拒絕。客戶端應(yīng)繼續(xù)發(fā)送請求的其余部分,如果請求已經(jīng)完成,則忽略該響應(yīng)。服務(wù)器必須在請求完成后發(fā)送最終響應(yīng)。有關(guān)使用和處理此狀態(tài)代碼的詳細討論,請參見第8.2.3節(jié)。
2.1.2 101切換協(xié)議 (Switching Protocols)
服務(wù)器已經(jīng)理解了客戶端的請求,并將通過 Upgrade 消息標(biāo)頭(第14.42節(jié))通知客戶端采用不同的協(xié)議來完成這個請求。在發(fā)送完這個響應(yīng)最后的空行后,服務(wù)器將會切換到在Upgrade 消息頭中定義的那些協(xié)議。只有在切換新的協(xié)議更有好處的時候才應(yīng)該采取類似措施。例如,切換到新的HTTP 版本比舊版本更有優(yōu)勢,或者切換到一個實時且同步的協(xié)議以傳送利用此類特性的資源。
2.2成功2xx
此類狀態(tài)碼表示客戶端的請求已成功接收,理解并被接受。
2.2.1 200 OK
此狀態(tài)碼指明客戶端請求已經(jīng)成功了。響應(yīng)返回的信息依賴于請求里的方法,例如:
GET 請求資源的相應(yīng)的實體已經(jīng)包含在響應(yīng)里并返回給客戶端。
HEAD 相應(yīng)于請求資源實體的實體標(biāo)頭已經(jīng)被包含在無消息主體的響應(yīng)里。
POST 響應(yīng)里已經(jīng)包含一個實體,此實體描述或者包含此POST動作執(zhí)行的結(jié)果
TRACE 響應(yīng)里包含一個實體,此實體包含終端對服務(wù)器接的請求消息。
2.2.2 201 已創(chuàng)建(Created)
請求已經(jīng)被服務(wù)器滿足了并且已經(jīng)產(chǎn)生了一個新的資源。新創(chuàng)建的資源的URI在響應(yīng)的實體里返回,但是此資源最確定的URI是在Location標(biāo)頭里給出的。響應(yīng)應(yīng)該含有一實體,此實體包含此資源的特性和位置,用戶或用戶代理能從這些特性和位置里選擇最合適的。實體格式被Content-Type標(biāo)頭里媒體類型指定。源服務(wù)器必須能在返回201狀態(tài)碼之前建立資源。如果動作(譯注:這里指能創(chuàng)建資源的方法,如POST方法)不能被立即執(zhí)行,那么服務(wù)器應(yīng)該以202(接受)響應(yīng)代替。
一個201響應(yīng)可以包含一個ETag響應(yīng)標(biāo)頭,此標(biāo)頭為請求的變量(譯注:變量的含義見第1.3節(jié)“變量”的解釋)指明當(dāng)前的實體標(biāo)簽(entity tag)值,當(dāng)資源被創(chuàng)建時,見14.19節(jié)。
場景詳解:因為 POST 請求對應(yīng)著 Create 操作,因此201通常用于 POST 請求。
2.2.3 202 接受(Accepted)
請求已經(jīng)被接受了,但是還沒有對此請求處理完。請求可能執(zhí)行也可能沒有不會執(zhí)行,因為當(dāng)執(zhí)行發(fā)生的時候服務(wù)器可能會發(fā)現(xiàn)此請求不能被執(zhí)行。
返回202狀態(tài)碼的響應(yīng)的目的是允許服務(wù)器接受其他過程的請求(例如某個每天只執(zhí)行一次的基于批處理的操作),而不必讓客戶端一直保持與服務(wù)器的連接直到批處理操作全部完成。在接受請求處理并返回202狀態(tài)碼的響應(yīng)應(yīng)當(dāng)在返回的實體中包含一些指示處理當(dāng)前狀態(tài)的信息,以及指向處理狀態(tài)監(jiān)視器或狀態(tài)預(yù)測的指針,以便用戶能夠估計操作是否已經(jīng)完成。
2.2.4 203 非權(quán)威信息(Non-Authoritative information)
服務(wù)器已成功處理了請求,但返回的實體頭部元信息不是在原始服務(wù)器上有效的確定集合,而是來自本地或者第三方的拷貝。當(dāng)前的信息可能是原始版本的子集或者超集。例如,包含資源的元數(shù)據(jù)可能是原始服務(wù)器元信息的超集。使用此狀態(tài)碼不是必須的,而且只有在響應(yīng)不使用此狀態(tài)碼便會返回200 OK的情況下才是合適的。
2.2.5 204 無內(nèi)容 (No Content)
服務(wù)器成功處理了請求,但不需要返回任何實體內(nèi)容,并且希望返回更新了的元信息。響應(yīng)可能通過實體頭部的形式,返回新的或更新后的元信息。如果存在這些頭部信息,則應(yīng)當(dāng)與所請求的變量相呼應(yīng)。
如果客戶端是瀏覽器的話,那么用戶瀏覽器應(yīng)保留發(fā)送了該請求的頁面,而不產(chǎn)生任何文檔視圖上的變化,即使按照規(guī)范新的或更新后的元信息應(yīng)當(dāng)被應(yīng)用到用戶瀏覽器活動視圖中的文檔。
由于204響應(yīng)被禁止包含任何消息體,因此它始終以消息頭后的第一個空行結(jié)尾。
場景詳解:需要提交數(shù)據(jù)到服務(wù)器,只需要返回是否成功的情況下,可以使用狀態(tài)碼204來作為返回,而瀏覽器不會刷新不會跳轉(zhuǎn);該狀態(tài)碼相較于200狀態(tài)碼因為沒有消息體更省流量,且200狀態(tài)碼可能會瀏覽器刷新、跳轉(zhuǎn)等副作用。適用于 PATCH、DELETE,PUT,如果是 POST 操作,應(yīng)返回201。
2.2.6 205 重置內(nèi)容(Reset Content)
205狀態(tài)響應(yīng)是服務(wù)器告訴用戶代理應(yīng)該重置引起請求被發(fā)送的文檔視圖。此響應(yīng)主要的目的是清空文檔視圖表單里的輸入框以便用戶能輸入其它信息。此響應(yīng)不能包含一個實體。
205和204的區(qū)別在于205需要用戶代理重置輸入表單,以便用戶繼續(xù)輸入
2.2.7 206 部分內(nèi)容(Partial Content)
服務(wù)器已經(jīng)成功處理了部分 GET 請求。類似于 FlashGet 或者迅雷這類的 HTTP 下載工具都是使用此類響應(yīng)實現(xiàn)斷點續(xù)傳或者將一個大文檔分解為多個下載段同時下載。
該請求必須包含 Range 標(biāo)頭(第14.35節(jié))信息來指示客戶端希望得到的內(nèi)容范圍,并且可能包含 If-Range (見第14.27節(jié))來作為請求條件。206狀態(tài)的響應(yīng)必須包含以下的標(biāo)頭:
- Content-Range 用以指示本次響應(yīng)中返回的內(nèi)容的范圍;如果是 Content-Type 為 multipart/byteranges 的多段下載,則每一 multipart 段中都應(yīng)包含 Content-Range 域用以指示本段的內(nèi)容范圍。假如響應(yīng)中包含 Content-Length,那么它的數(shù)值必須匹配它返回的內(nèi)容范圍的真實字節(jié)數(shù)。
- Date標(biāo)頭
- ETag 和/或 Content-Location標(biāo)頭,假如請求一樣應(yīng)該返回200響應(yīng)。
- Expire,Cache-Control,和/或者Vary標(biāo)頭,假如其值可能與之前相同變量的其他響應(yīng)對應(yīng)的值不同的話。
如果206響應(yīng)是使用了強緩存驗證(見第13.3.3節(jié))的If-Range請求的結(jié)果,那么此響應(yīng)不應(yīng)該包含其他的實體標(biāo)頭。如果響應(yīng)是使用了弱緩存驗證的If-Range請求的結(jié)果,那么響應(yīng)不能包含其他的實體標(biāo)頭;這能防止出現(xiàn)在緩存的實體主體和更新的標(biāo)頭之間的不一致性。其他的情況下,響應(yīng)必須包含所有的實體標(biāo)頭,這些標(biāo)頭可能已經(jīng)在以前的相同請求的200響應(yīng)里返回過。
緩存不能把206響應(yīng)和以前的緩存內(nèi)容結(jié)合如果ETag或Last-Modified標(biāo)頭并不能精確匹配,見第13.5.4節(jié)。
假如本響應(yīng)請求使用了 If-Range 強緩存驗證,那么本次響應(yīng)不應(yīng)該包含其他實體頭;假如本響應(yīng)的請求使用了 If-Range 弱緩存驗證,那么本次響應(yīng)禁止包含其他實體頭;這避免了緩存的實體內(nèi)容和更新了的實體頭信息之間的不一致。否則,本響應(yīng)就應(yīng)當(dāng)包含所有本應(yīng)該返回200響應(yīng)中應(yīng)當(dāng)返回的所有實體頭部域。
假如 ETag 或 Last-Modified 頭部不能精確匹配的話,則客戶端緩存應(yīng)禁止將206響應(yīng)返回的內(nèi)容與之前任何緩存過的內(nèi)容組合在一起。任何不支持 Range 以及 Content-Range 頭的緩存都禁止緩存206響應(yīng)返回的內(nèi)容。
2.3 重新定向 3xx
這類狀態(tài)碼指明用戶代理需要更進一步的動作去完成請求。進一步的動作可能被用戶代理自動執(zhí)行而不需要用戶的交互,并且進一步動作請求的方法必須為GET或HEAD??蛻舳藨?yīng)該發(fā)現(xiàn)無限的重定向回路,因為此回路能產(chǎn)生網(wǎng)絡(luò)擁擠。
被請求的資源有一系列可供選擇的回饋信息,每個都有自己特定的地址和客戶端驅(qū)動的商議信息。客戶端能夠自行選擇一個首選的地址進行重定向。
除非這是一個 HEAD 請求,否則該響應(yīng)應(yīng)當(dāng)包括一個資源特性及地址的列表的實體,以便用戶代理從中選擇最合適的重定向地址。這個實體的格式由 Content-Type 定義的格式所決定。用戶代理可能根據(jù)響應(yīng)的格式以及用戶代理自身能力,自動作出最合適的選擇。當(dāng)然,RFC 2616規(guī)范并沒有規(guī)定這樣的自動選擇該如何進行。
如果服務(wù)器本身已經(jīng)有了首選的回饋選擇,那么在 Location 中應(yīng)當(dāng)指明這個回饋的 URI;用戶代理可能會將這個 Location 值作為自動重定向的地址。此外,除非額外指定,否則這個響應(yīng)也是可緩存的。注意:以前此規(guī)范版本建議一個資源最多能有五個重定向。內(nèi)容開發(fā)者應(yīng)該知道客戶端可能存在這個限制。
2.3.1 300 多個選擇.(Multiple Choices)
資源對應(yīng)有多個表現(xiàn)形式,客戶端請求資源的表現(xiàn)形式對應(yīng)于其中的一個,每個表現(xiàn)形式都有一個指向自己的位置(location),并且代理驅(qū)動協(xié)商(agent-driven negotiation)能選擇一個更適的表現(xiàn)形式并重定向請求到那個表現(xiàn)形式的位置。
除非是HEAD請求,否則300狀態(tài)響應(yīng)應(yīng)該包含一個實體,此實體包含一個資源特性和位置列表,從這個列表里用戶或用戶代理能選擇最合適的資源的表現(xiàn)形式。實體格式被Content-Type標(biāo)頭里的媒體類型指定。依賴于此格式和用戶代理的能力,用戶代理選擇最合適的表現(xiàn)形式的行為可能會被自動執(zhí)行。然而,此規(guī)范并沒有定義自動執(zhí)行行為的標(biāo)準(zhǔn)。
如果服務(wù)器能確定更好的表現(xiàn)形式,它應(yīng)該為此表現(xiàn)形式在Location標(biāo)頭里包含一個特定的URI來指明此表現(xiàn)形式的位置;用戶代理可能會利用此Location標(biāo)頭自動重定向。300狀態(tài)響應(yīng)是可緩存的除非被特別指明。
2.3.2 301 永久移動 (Moved Permanently)
請求資源被賦于一個新的永久的URI,并且任何將來對此資源的引用都會利用此301狀態(tài)響應(yīng)返回的URI。如果可能,擁有鏈接編輯功能的客戶端應(yīng)當(dāng)自動把請求的地址修改為從服務(wù)器反饋回來的地址。此響應(yīng)是能緩存的除非另外聲明。
新的永久性的 URI 應(yīng)當(dāng)在響應(yīng)的 Location 域中返回。除非這是一個 HEAD 請求,否則響應(yīng)的實體中應(yīng)當(dāng)包含指向新的 URI 的超鏈接及簡短說明。
如果這不是一個 GET 或者 HEAD 請求,用戶代理不能自動進行重定向,除非得到用戶的確認(rèn),因為請求的條件可能因此發(fā)生變化。
注意:對于某些使用 HTTP/1.0 協(xié)議的瀏覽器,當(dāng)它們發(fā)送的 POST 請求得到了一個301響應(yīng)的話,接下來的重定向請求將會錯誤的變成 GET 方式。
2.3.3 302 發(fā)現(xiàn)(Found)
請求的資源現(xiàn)在臨時從不同的 URI 響應(yīng)請求。由于這樣的重定向是臨時的,客戶端應(yīng)當(dāng)繼續(xù)向原有地址發(fā)送以后的請求。只有在Cache-Control或Expires中進行了指定的情況下,這個響應(yīng)才是可緩存的。
新的臨時性的 URI 應(yīng)當(dāng)在響應(yīng)的 Location 域中返回。除非這是一個 HEAD 請求,否則響應(yīng)的實體中應(yīng)當(dāng)包含指向新的 URI 的超鏈接及簡短說明。
如果這不是一個 GET 或者 HEAD 請求,那么瀏覽器禁止自動進行重定向,除非得到用戶的確認(rèn),因為請求的條件可能因此發(fā)生變化。
注意:雖然RFC 1945和RFC 2068規(guī)范不允許客戶端在重定向時改變請求的方法,但是很多現(xiàn)存的瀏覽器將302響應(yīng)視作為303響應(yīng),并且使用 GET 方式訪問在 Location 中規(guī)定的 URI,而無視原先請求的方法。狀態(tài)碼303和307被添加了進來,用以明確服務(wù)器期待客戶端進行何種反應(yīng)。
2.3.4 303 見其他(See Other)
對應(yīng)當(dāng)前請求的響應(yīng)可以在另一個 URI 上被找到,而且客戶端應(yīng)當(dāng)采用 GET 的方式訪問那個資源。這個方法的存在主要是為了允許由腳本激活的POST請求輸出重定向到一個新的資源。這個新的 URI 不是原始資源的替代引用。同時,303響應(yīng)禁止被緩存。當(dāng)然,第二個請求(重定向)可能被緩存。
新的 URI 應(yīng)當(dāng)在響應(yīng)的 Location 域中返回。除非這是一個 HEAD 請求,否則響應(yīng)的實體中應(yīng)當(dāng)包含指向新的 URI 的超鏈接及簡短說明。
注意:許多 HTTP/1.1 版以前的 瀏覽器不能正確理解303狀態(tài)。如果需要考慮與這些瀏覽器之間的互動,302狀態(tài)碼應(yīng)該可以勝任,因為大多數(shù)的瀏覽器處理302響應(yīng)時的方式恰恰就是上述規(guī)范要求客戶端處理303響應(yīng)時應(yīng)當(dāng)做的。
2.3.5 304 沒有被改變(Not Modified)
如果客戶端發(fā)送了一個帶條件的 GET 請求且該請求已被允許,而文檔的內(nèi)容(自上次訪問以來或者根據(jù)請求的條件)并沒有改變,則服務(wù)器應(yīng)當(dāng)返回這個狀態(tài)碼。304響應(yīng)禁止包含消息體,因此始終以消息頭后的第一個空行結(jié)尾。
此響應(yīng)必須包含下面的標(biāo)頭:
- Date,除非這個服務(wù)器沒有時鐘。假如沒有時鐘的服務(wù)器也遵守這些規(guī)則,那么代理服務(wù)器以及客戶端可以自行將 Date 字段添加到接收到的響應(yīng)頭中去(這在RFC 2086里聲明了,見14.19節(jié)),緩存機制將會正常工作。
- ETag 和/或 Content-Location,假如同樣的請求本應(yīng)返回200響應(yīng)。
- Expires, Cache-Control,和/或Vary,假如其值可能與之前相同變量的其他響應(yīng)對應(yīng)的值不同的話。
假如本響應(yīng)請求使用了強緩存驗證,那么本次響應(yīng)不應(yīng)該包含其他實體頭;否則(例如,某個帶條件的 GET 請求使用了弱緩存驗證),本次響應(yīng)禁止包含其他實體頭;這避免了緩存了的實體內(nèi)容和更新了的實體頭信息之間的不一致。
假如某個304響應(yīng)指明了當(dāng)前某個實體沒有緩存,那么緩存系統(tǒng)必須忽視這個響應(yīng),并且重復(fù)發(fā)送不包含限制條件的請求。
假如接收到一個要求更新某個緩存條目的304響應(yīng),那么緩存系統(tǒng)必須更新整個條目以反映所有在響應(yīng)中被更新的字段的值。
使用場景:所有 GET 請求都建議遵循該協(xié)議,實踐中,對于資源類的請求建議使用 ETag 做標(biāo)記;對于數(shù)據(jù)類的可以使用 ETag 也可以使用Last-Modified
2.3.6 305 使用代理服務(wù)器 (User Proxy)
被請求的資源必須通過指定的代理才能被訪問。Location 域中將給出指定的代理所在的 URI 信息,接收者需要重復(fù)發(fā)送一個單獨的請求,通過這個代理才能訪問相應(yīng)資源。只有原始服務(wù)器才能建立305響應(yīng)。
注意:RFC 2068并沒有說明305響應(yīng)的目的是重定向一個獨立請求,并且只能被源服務(wù)器產(chǎn)生。不注意這些限制會有重要的安全后果。
2.3.7 306沒有使用的(unused)
306狀態(tài)碼被用于此規(guī)范以前的版本,是不再使用的意思,并且此狀態(tài)碼被保留。
2.3.8 307臨時重發(fā)(Temporary Redirect)
請求的資源現(xiàn)在臨時從不同的URI 響應(yīng)請求。由于這樣的重定向是臨時的,客戶端應(yīng)當(dāng)繼續(xù)向原有地址發(fā)送以后的請求。只有在Cache-Control或Expires中進行了指定的情況下,這個響應(yīng)才是可緩存的。
新的臨時性的URI 應(yīng)當(dāng)在響應(yīng)的 Location 域中返回。除非這是一個HEAD 請求,否則響應(yīng)的實體中應(yīng)當(dāng)包含指向新的URI 的超鏈接及簡短說明。因為部分瀏覽器不能識別307響應(yīng),因此需要添加上述必要信息以便用戶能夠理解并向新的 URI 發(fā)出訪問請求。
如果這不是一個GET 或者 HEAD 請求,那么用戶代理禁止自動進行重定向,除非得到用戶的確認(rèn),因為請求的條件可能因此發(fā)生變化。
2.4 客戶端錯誤 4xx
4xx類的狀態(tài)代碼適用于客戶端似乎有錯誤的情況。除了響應(yīng)HEAD請求之外,服務(wù)器應(yīng)該包含一個包含錯誤情況說明的實體,以及它是一個臨時的還是永久的。這些狀態(tài)碼適用于任何請求方式。用戶代理應(yīng)該向用戶顯示任何包含的實體。
如果客戶端正在發(fā)送數(shù)據(jù),則在服務(wù)器關(guān)閉輸入連接之前,使用TCP的服務(wù)器實現(xiàn)應(yīng)該小心,以確??蛻舳舜_認(rèn)收到包含響應(yīng)的數(shù)據(jù)包。如果客戶端在關(guān)閉后繼續(xù)向服務(wù)器發(fā)送數(shù)據(jù),則服務(wù)器的TCP堆棧將向客戶端發(fā)送重置數(shù)據(jù)包,這可能會擦除客戶端未確認(rèn)的輸入緩沖區(qū),然后才能被HTTP應(yīng)用程序讀取和解釋。
2.4.1 400 壞請求(Bad Request)
由于語義或參數(shù)錯誤,服務(wù)器無法理解該請求。除非進行修改,否則客戶端不應(yīng)該重復(fù)提交這個請求。
2.4.2 401 未授權(quán)的 (Unauthorized)
當(dāng)前請求需要用戶驗證。該響應(yīng)必須包含一個適用于被請求資源的 WWW-Authenticate(見14.47) 信息頭用以詢問用戶信息??蛻舳丝梢灾貜?fù)提交一個包含恰當(dāng)?shù)?Authorization 頭信息的請求。如果當(dāng)前請求已經(jīng)包含了 Authorization 證書,那么401響應(yīng)代表著服務(wù)器驗證已經(jīng)拒絕了那些證書。如果401響應(yīng)包含了與前一個響應(yīng)相同的身份驗證詢問,且瀏覽器已經(jīng)至少嘗試了一次驗證,那么瀏覽器應(yīng)當(dāng)向用戶展示響應(yīng)中包含的實體信息,因為這個實體信息中可能包含了相關(guān)診斷信息。參見RFC 2617。
應(yīng)用場景:凡是需要授權(quán)才能進行的操作,而驗簽失敗時均可返回該狀態(tài)碼。例如 token 錯誤、token 失效、令牌錯誤、證書錯誤、用戶名密碼錯誤等。
2.4.3 402 支付需要 (Payment Required)
此代碼保留供將來使用。
2.4.4 403 禁用 (Forbidden)
服務(wù)器已經(jīng)理解請求,但是拒絕執(zhí)行它。與401響應(yīng)不同的是,身份驗證并不能提供任何幫助,而且這個請求也不應(yīng)該被重復(fù)提交。如果這不是一個 HEAD 請求,而且服務(wù)器希望能夠講清楚為何請求不能被執(zhí)行,那么就應(yīng)該在實體內(nèi)描述拒絕的原因。如果它不希望讓客戶端獲得被拒原因,服務(wù)器也可以返回一個404響應(yīng)。
2.4.5 404 沒有找到(Not Found)
請求失敗,請求所希望得到的資源未被在服務(wù)器上發(fā)現(xiàn)。沒有信息能夠告訴用戶這個狀況到底是暫時的還是永久的。假如服務(wù)器知道情況的話,應(yīng)當(dāng)使用410狀態(tài)碼來告知舊資源因為某些內(nèi)部的配置機制問題,已經(jīng)永久的不可用,而且沒有任何可以跳轉(zhuǎn)的地址。404這個狀態(tài)碼被廣泛應(yīng)用于當(dāng)服務(wù)器不想揭示到底為何請求被拒絕或者沒有其他適合的響應(yīng)可用的情況下。
2.4.6 405 不被允許的方法(Method Not Allowed)
請求行中指定的請求方法不能被用于請求相應(yīng)的資源。該響應(yīng)必須返回一個 Allow 頭信息用以表示出當(dāng)前資源能夠接受的請求方法的列表。
鑒于 PUT,DELETE 方法會對服務(wù)器上的資源進行寫操作,因而絕大部分的網(wǎng)頁服務(wù)器都不支持或者在默認(rèn)配置下不允許上述請求方法,對于此類請求均會返回405錯誤。
2.4.7 406 不接受的 (Not Acceptable)
如果響應(yīng)是不可接受的,用戶代理應(yīng)該暫時停止更多的數(shù)據(jù)的接收并且詢問用戶去決定進一步的動作。
請求的資源的內(nèi)容特性無法滿足請求頭中的條件,因而無法生成響應(yīng)實體。
除非這是一個 HEAD 請求,否則該響應(yīng)就應(yīng)當(dāng)返回一個包含可以讓用戶或者瀏覽器從中選擇最合適的實體特性以及地址列表的實體。實體的格式由 Content-Type 頭中定義的媒體類型決定。瀏覽器可以根據(jù)格式及自身能力自行作出最佳選擇。但是,規(guī)范中并沒有定義任何作出此類自動選擇的標(biāo)準(zhǔn)。
注意:HTTP/1.1服務(wù)器被允許返回這樣的響應(yīng),此響應(yīng)根據(jù)接受標(biāo)頭(如:Accept, Accept-Charset, Accept-Encoding, or Accept-Language)是不可接受的。在一些情況下,這可能更傾向于發(fā)送一個406響應(yīng)。用戶代理被鼓勵觀察響應(yīng)來決定是否此響應(yīng)是可接受的。
2.4.8 407 代理服務(wù)器授權(quán)所需(Proxy Authentication Required)
與401響應(yīng)類似,只不過客戶端必須在代理服務(wù)器上進行身份驗證。代理服務(wù)器必須返回一個 Proxy-Authenticate(見14.33節(jié))用以進行身份詢問??蛻舳丝梢苑祷匾粋€ Proxy-Authorization 信息頭用以驗證(第14.34節(jié))。HTTP訪問認(rèn)證在“HTTP認(rèn)證:基本和摘要訪問認(rèn)證” [43]中進行了說明。
2.4.9 408 請求超時(Request Timeout)
請求超時??蛻舳藳]有在服務(wù)器預(yù)備等待的時間內(nèi)完成一個請求的發(fā)送。客戶端可以隨時再次提交這一請求而無需進行任何更改。
2.4.10 409 沖突 (Confilict)
由于和被請求的資源的當(dāng)前狀態(tài)之間存在沖突,請求無法完成。這個代碼只允許用在這樣的情況下才能被使用:用戶被認(rèn)為能夠解決沖突,并且會重新提交新的請求。該響應(yīng)應(yīng)當(dāng)包含足夠的信息以便用戶發(fā)現(xiàn)沖突的源頭。
沖突通常發(fā)生于對 PUT 請求的處理中。例如,在采用版本檢查的環(huán)境下,某次 PUT 提交的對特定資源的修改請求所附帶的版本信息與之前的某個(第三方)請求向沖突,那么此時服務(wù)器就應(yīng)該返回一個409錯誤,告知用戶請求無法完成。此時,響應(yīng)實體中很可能會包含兩個沖突版本之間的差異比較,以便用戶重新提交歸并以后的新版本。
2.4.11 410 不存在(gone)
被請求的資源在服務(wù)器上已經(jīng)不再可用,而且沒有任何已知的轉(zhuǎn)發(fā)地址。這樣的狀況應(yīng)當(dāng)被認(rèn)為是永久性的。如果可能,擁有鏈接編輯功能的客戶端應(yīng)當(dāng)在獲得用戶許可后刪除所有指向這個地址的引用。如果服務(wù)器不知道或者無法確定這個狀況是否是永久的,那么就應(yīng)該使用404狀態(tài)碼。除非額外說明,否則這個響應(yīng)是可緩存的。
410響應(yīng)的目的主要是幫助網(wǎng)站管理員維護網(wǎng)站,通知用戶該資源已經(jīng)不再可用,并且服務(wù)器擁有者希望所有指向這個資源的遠端連接也被刪除。這類事件在限時、增值服務(wù)中很普遍。同樣,410響應(yīng)也被用于通知客戶端在當(dāng)前服務(wù)器站點上,原本屬于某個個人的資源已經(jīng)不再可用。當(dāng)然,是否需要把所有永久不可用的資源標(biāo)記為'410 Gone',以及是否需要保持此標(biāo)記多長時間,完全取決于服務(wù)器擁有者。
2.4.12 411 必需的長度 (Length Required)
服務(wù)器拒絕在沒有定義 Content-Length 頭的情況下接受請求。在添加了表明請求消息體長度的有效 Content-Length 頭之后,客戶端可以再次提交該請求。
2.4.13 412 先決條件失敗 (Precondition Failed)
服務(wù)器在驗證在請求的頭字段中給出先決條件時,沒能滿足其中的一個或多個。這個狀態(tài)碼允許客戶端在獲取資源時在請求的元信息(請求頭字段數(shù)據(jù))中設(shè)置先決條件,以此避免該請求方法被應(yīng)用到其希望的內(nèi)容以外的資源上。
2.4.14 413 請求實體太大
服務(wù)器拒絕處理當(dāng)前請求,因為該請求提交的實體數(shù)據(jù)大小超過了服務(wù)器愿意或者能夠處理的范圍。此種情況下,服務(wù)器可以關(guān)閉連接以免客戶端繼續(xù)發(fā)送此請求。
如果這個狀況是臨時的,服務(wù)器應(yīng)當(dāng)返回一個 Retry-After 的響應(yīng)頭,以告知客戶端可以在多長時間以后重新嘗試。
2.4.15 414 請求URI太長(Request-URI Too Long)
請求的URI 長度超過了服務(wù)器能夠解釋的長度,因此服務(wù)器拒絕對該請求提供服務(wù)。這比較少見,通常的情況包括:
本應(yīng)使用POST方法的表單提交變成了GET方法,導(dǎo)致查詢字符串(Query String)過長。
重定向URI “黑洞”,例如每次重定向把舊的 URI 作為新的 URI 的一部分,導(dǎo)致在若干次重定向后 URI 超長。客戶端正在嘗試?yán)媚承┓?wù)器中存在的安全漏洞攻擊服務(wù)器。這類服務(wù)器使用固定長度的緩沖讀取或操作請求的 URI,當(dāng) GET 后的參數(shù)超過某個數(shù)值后,可能會產(chǎn)生緩沖區(qū)溢出,導(dǎo)致任意代碼被執(zhí)行[1]。沒有此類漏洞的服務(wù)器,應(yīng)當(dāng)返回414狀態(tài)碼。
2.4.16 415 不被支持的媒體類型(Unsupported Media Type)
對于當(dāng)前請求的方法和所請求的資源,請求中提交的實體并不是服務(wù)器中所支持的格式,因此請求被拒絕。
2.4.17 416 請求范圍不滿足 (Requested Range Not Satisfiable)
如果請求中包含了 Range 請求頭,并且 Range 中指定的任何數(shù)據(jù)范圍都與當(dāng)前資源的可用范圍不重合,同時請求中又沒有定義 If-Range 請求頭,那么服務(wù)器就應(yīng)當(dāng)返回416狀態(tài)碼。
假如 Range 使用的是字節(jié)范圍,那么這種情況就是指請求指定的所有數(shù)據(jù)范圍的首字節(jié)位置都超過了當(dāng)前資源的長度。服務(wù)器也應(yīng)當(dāng)在返回416狀態(tài)碼的同時,包含一個 Content-Range 實體頭,用以指明當(dāng)前資源的長度。這個響應(yīng)也被禁止使用 multipart/byteranges 作為其 Content-Type。
2.4.18 417期望失敗
在請求頭 Expect (見第14.20節(jié))中指定的預(yù)期內(nèi)容無法被服務(wù)器滿足,或者這個服務(wù)器是一個代理服務(wù)器,它有明顯的證據(jù)證明在當(dāng)前路由的下一個節(jié)點上,Expect 的內(nèi)容無法被滿足。
2.4.19 422 Unprocessable Entity
無法處理的請求實體。
2.4.20 423 Locked
當(dāng)前資源被鎖定。(RFC 4918 WebDAV)
2.4.21 424 Failed Dependency
由于之前的某個請求發(fā)生的錯誤,導(dǎo)致當(dāng)前請求失敗,例如 PROPPATCH。(RFC 4918 WebDAV)
2.5 服務(wù)器錯誤 5xx (Server Error)
這類狀態(tài)碼指明服務(wù)器處理請求時產(chǎn)生錯誤或不能處理請求。除了HEAD請求,服務(wù)器應(yīng)該包含一個實體,此實體用來解釋錯誤,和是否是暫時或長期條件。用戶代理應(yīng)該展示實體給用戶。此響應(yīng)狀態(tài)碼能應(yīng)用于任何請求方法。
2.5.1 500 服務(wù)器內(nèi)部錯誤 (Internal Server Error)
服務(wù)器遇到了一個未曾預(yù)料的狀況,導(dǎo)致了它無法完成對請求的處理。一般來說,這個問題都會在服務(wù)器的程序碼出錯時出現(xiàn)。
2.5.2 501 不能實現(xiàn) (Not Implemented)
服務(wù)器不支持當(dāng)前請求所需要的某個功能。當(dāng)服務(wù)器無法識別請求的方法,并且無法支持其對任何資源的請求。
2.5.3 502 壞網(wǎng)關(guān) (Bad Gateway)
作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請求時,從上游服務(wù)器接收到無效的響應(yīng)。
2.5.4 503 服務(wù)不可用.(Service Unavailable)
由于臨時的服務(wù)器維護或者過載,服務(wù)器當(dāng)前無法處理請求。這個狀況是臨時的,并且將在一段時間以后恢復(fù)。如果能夠預(yù)計延遲時間,那么響應(yīng)中可以包含一個 Retry-After 頭用以標(biāo)明這個延遲時間。如果沒有給出這個 Retry-After 信息,那么客戶端應(yīng)當(dāng)以處理500響應(yīng)的方式處理它。
注意:503狀態(tài)碼的存在并不意味著服務(wù)器在重載時必須使用它。有些服務(wù)器可能希望簡單地拒絕連接。
2.5.5 504 網(wǎng)關(guān)超時(Gateway Timeout)
作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請求時,未能及時從上游服務(wù)器(URI標(biāo)識出的服務(wù)器,例如HTTP、FTP、LDAP)或者輔助服務(wù)器(例如DNS)收到響應(yīng)。
注意:某些代理服務(wù)器在DNS查詢超時時會返回400或者500錯誤
2.5.6 505 HTTP版本不支持(HTTP version Not Supported)
服務(wù)器不支持,或者拒絕支持在請求中使用的 HTTP 版本。這暗示著服務(wù)器不能或不愿使用與客戶端相同的版本。響應(yīng)中應(yīng)當(dāng)包含一個描述了為何版本不被支持以及服務(wù)器支持哪些協(xié)議的實體。
2.5.7 507
服務(wù)器無法存儲完成請求所必須的內(nèi)容。這個狀況被認(rèn)為是臨時的。WebDAV (RFC 4918)
2.5.8 509
服務(wù)器達到帶寬限制。這不是一個官方的狀態(tài)碼,但是仍被廣泛使用。
2.5.9 510
獲取資源所需要的策略并沒有沒滿足。(RFC 2774)