HTTP 狀態碼詳解

openkk 12年前發布 | 41K 次閱讀 HTTP

最近看《REST in Practice》,發現 HTTP 如此之多的狀態碼都有各自的含義,要準確使用并不難,但現實當中很少人能夠做得到。大多數人熟悉的狀態碼就那幾個,平時也不會去閱讀 RFC 2616,結果反復使用的也就是那幾個狀態碼。其實很多 REST 中可能遇到的情況,在 HTTP 狀態碼中都已經有考慮到,不需要自己去發明新的狀態碼,也不需要在 header 或者 body 自定義錯誤信息。

在說狀態碼之前,首先建議大家還是先閱讀一下 RFC 2616 中的相關章節,看看已有的狀態碼描述都是什么。我相信有部分狀態碼是你看了描述也不知道用來干什么的,這時候就需要有更具體的例子來告訴你怎么用了。(我準備詳細說的是那些比較少人知道但又實際上應該被更廣泛使用的狀態碼。)

2xx

200 OK

所有人都知道 200 OK 是什么。這估計是最經常被濫用的狀態碼。很多人在應該使用其它 2xx 狀態碼時都選用了 200 OK 來表示。

201 Created

如果你在設計一個 REST API,或者一個 CRUD API,當你使用 POST(或者 PUT)成功創建一個新的資源后,服務器應該返回 201 Created 同時在 header 的 Location 字段給出剛剛創建好的這個資源的 URI。

例如說,如果你使用 POST 請求通過 \comments URI 創建了一個新的評論,那么服務器應該返回 201 Created,同時帶上形如 Location: \comments\1234 的字段表明新創建的評論的 URI。

202 Accepted

如果服務器在接受請求后,需要進行一個異步處理才能有結果,并且覺得不需要讓 TCP 連接保持到結果出來再返回,它可以返回 202 Accepted,意思是請求已接受,但沒有立即可返回的結果。

204 No Content

在一個 REST API 或者 CRUD API 里面,當你使用 PUT 成功更新一個資源后,如果服務器完整接受了客戶端的更新,沒有拒絕也沒有額外更新,那實際上是不需要返回任何東西的,因為現在客戶端和服務器端已經擁有完全一致的狀態。在這種情況下,服務器可以返回 204 No Content,同時 body 為空,客戶端就知道它的狀態已經跟服務器端同步了。

206 Partial Content

斷點續傳和多線程下載都是通過 206 Partial Content 實現的。

請求的 header 必須包含一個 Range 字段,表明自己請求第幾個字節到第幾個字節的內容。如果服務器支持的話,就返回 206 Partial Content,然后使用 header 的 Content-Range 指明范圍,并在 body 內提供這個范圍內的數據。

3xx

301 Moved Permanently

永久性重定向。目標由 header 的 Location 字段給出,同時 body 中也應該有指向目標的鏈接。新請求使用的方法應該和原請求的一致。如果用戶使用 HEADGET 以外的方式發起原請求,客戶端在遇到 301 Moved Permanently 后應當詢問用戶是否對新的 URI 發起新請求。

302 Found

臨時性重定向。

這應該是瀏覽器實現最不符合標準的一個狀態碼了。理論上,除了臨時性這一點,302 Found301 Moved Permanently 應該是完全一樣的。然而實質上,很多瀏覽器在遇到 302 Found 后就會使用 GET 去請求新的 URI,而無論原請求使用的是何種方法。由于這種現象的普遍存在,使得這成為了一個與書面標準相違背的事實標準,新的客戶端在實現時很難選擇應該遵守哪一個標準,所以 RFC 2616 專門新增了 303 See Other307 Temporary Redirect 兩個狀態碼來消除二義性。

303 See Other

臨時性重定向,且總是使用 GET 請求新的 URI。

304 Not Modified

如果客戶端發起了一個「條件 GET」,同時資源確實沒被修改過,那么服務器端就應該返回 304 Not Modified,同時 body 不包含任何內容。

所謂的「條件 GET」,是指 GET 的 header 帶上了 If-Modified-SinceIf-None-Match 字段。這兩個 header 就是「條件」,如果條件符合了 GET 就應該正常執行,否則就應該返回 304 Not Modified,以便告訴客戶端它想要請求的資源在上一次請求之后沒有被更新過,客戶端可以繼續使用之前的版本。

307 Temporary Redirect

臨時性重定向,且總是使用原請求的方法來進行新請求。

4xx

400 Bad Request

服務器無法理解請求的格式,客戶端不應當嘗試再次使用相同的內容發起請求。

401 Unauthorized

請求未授權。如果請求 header 沒有 Authorization 字段,服務器端應該在返回 401 Unauthorized 的同時在 header 中用 WWW-Authorization 字段指出授權方式,以便客戶端帶上登錄信息重新發起請求。如果 Authorization 字段已經存在,則表明登錄信息不正確。

402 Payment Required

需要支付。這是一個在任何瀏覽器中都沒有被實現的狀態碼,僅預留將來使用。

百度曾經有一個部門印過一批背上寫著 402 Payment Require 的衣服,并且開玩笑說這批衣服最適合在互聯網企業員工討薪時穿。

403 Forbidden

禁止訪問。即使使用 Authorization 字段提供登錄信息也會得到相同的結果。

如果客戶端使用 HEAD 以外的方法請求,403 Forbidden 必須同時在 body 中返回禁止訪問的原因。如果原因不能夠公開,則應該使用 404 Not Found

404 Not Found

找不到如何與 URI 相匹配的資源。服務器無需指出資源是臨時性不存在還是永久性不存在,但如果服務器端知道該資源已經被永久性刪除則應該返回 410 Gone

404 Not Found 是服務器端在不愿意提供理由的情況下拒絕提供資源的最佳借口。

405 Method Not Allowed

請求的方法被拒絕。

如果你有一個 REST API 或 CRUD API 被設計為只讀,那么在遇到 PUTPOST 或者 DELETE 方法時服務器端都應該返回 405 Method Not Allowed,同時在 header 的 Allow 字段說明允許的方法(如 GETHEAD)。

409 Conflict

沖突,且需要用戶手工解決。

如果你使用 git(或者其他源代碼管理軟件),你已經知道「沖突」是什么了。409 Conflict 通常發生在 PUT 請求時,如果要更新的資源已經被其他人更新過了,你再更新就可能產生沖突。

410 Gone

如果服務器端將此資源標記為已被永久性刪除,則應該使用 410 Gone 而非 404 Not Found,其用意在于告訴客戶端資源是被有意刪除的,而且刪除是永久性的,客戶端不應該再保留這個 URI 的鏈接。

舉例來說,你有一個 REST API 或 CRUD API 用于向用戶提供優惠信息。有一則優惠的 URI 是 /promotions/1234,但由于優惠活動已經結束了,所以這一則優惠信息不再有效且應當被永久性刪除,那么這時候服務器端就應該讓該 URI 永遠返回 410 Gone 了。

412 Precondition Failed

條件判斷失敗,操作不會被執行。

在解釋 304 Not Modified 時提到了「條件 GET」的概念,但「條件」本身也可以應用于非 GET 請求,這時候如果條件判斷失敗服務器端就應該返回 412 Precondition Failed,同時拒絕執行客戶端請求的方法。

條件請求可以被看作是一種樂觀鎖。它不需要服務器端有任何邏輯判斷操作是否存在沖突,服務器端只要記錄資源的時間戳(或其它版本信息)即可。

5xx

500 Internal Server Error

最常見的服務器端錯誤。

503 Service Unavailable

服務器端暫時無法處理請求(可能是過載或維護)。

返回 503 Service Unavailable 的意思是當前的狀況是臨時性的,客戶端可以稍后重試。服務器端可以在返回時通過 header 的 Retry-After 字段告訴客戶端多久后可以重試。如果不提供這個字段的話,客戶端應當把 503 Service Unavailable 等同于 500 Internal Server Error 處理。

總結

在看完這篇文章后,你有發現經常用錯的狀態碼嗎?如果有的話,將來在設計 REST API 或 CRUD API 時就應該改過來。由于狀態碼和 header 字段數目眾多,所以我建議一般用戶盡可能復用主流的 REST 框架或 CRUD 框架,而不要自己重新實現一遍。

轉自:http://www.cnblogs.com/cathsfz/archive/2012/06/19/2553431.html

 本文由用戶 openkk 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!