楔子
我們已經學習了 HTTP 報文里請求行的組成部分,包括請求方法和 URI。有了請求行,加上后面的頭字段就形成了請求頭,可以通過 TCP/IP 協議發送給服務器。服務器收到請求報文,解析后需要進行處理,具體的業務邏輯多種多樣,但最后必定是拼出一個響應報文發回客戶端。響應報文由響應頭加響應體數據組成,響應頭又由狀態行和頭字段構成。而我們說狀態行有三部分:
開頭的 Version 部分是 HTTP 協議的版本號,通常是 HTTP/1.1,用處不是很大。后面的 Reason 部分是原因短語,是狀態碼的簡短文字描述,例如 OK、Not Found 等等,也可以自定義。但它只是為了兼容早期的文本客戶端而存在,提供的信息很有限,目前的大多數客戶端都會忽略它。所以,狀態行里有用的就只剩下中間的狀態碼(Status Code)了。它是一個十進制數字,以代碼的形式表示服務器對請求的處理結果,就像我們通常編寫程序時函數返回的錯誤碼一樣。
不過你要注意,它的名字是狀態碼、而不是錯誤碼。也就是說,它的含義不僅是錯誤,更重要的意義在於表達 HTTP 數據處理的狀態,客戶端可以依據代碼適時轉換處理狀態,例如繼續發送請求、切換協議,重定向跳轉等,有那么點 TCP 狀態轉換的意思。
狀態碼
目前 RFC 標准里規定的狀態碼是三位數,所以取值范圍就是從 000 到 999。但如果把代碼簡單地從 000 開始順序編下去就顯得有點太 low,不靈活、不利於擴展,所以狀態碼也被設計成有一定的格式。RFC 標准把狀態碼分成了五類,用數字的第一位表示分類,而 0~99 不用,這樣狀態碼的實際可用范圍就大大縮小了,由 000~999 變成了 100~599。這五類的具體含義是:
1xx
1xx 類狀態碼屬於提示信息,是協議處理中的一種中間狀態,實際用到的比較少。
2xx
2xx 類狀態碼表示服務器成功處理了客戶端的請求,也是我們最願意看到的狀態。
「200 OK」是最常見的成功狀態碼,表示一切正常。如果是非 HEAD 請求,服務器返回的響應頭都會有 body 數據
「204 No Content」也是常見的成功狀態碼,與 200 OK 基本相同,但響應頭沒有 body 數據
「206 Partial Content」是應用於 HTTP 分塊下載或斷電續傳,表示響應返回的 body 數據並不是資源的全部,而是其中的一部分,也是服務器處理成功的狀態
3xx
3xx 類狀態碼表示客戶端請求的資源發送了變動,需要客戶端用新的 URL 重新發送請求獲取資源,也就是重定向。
「301 Moved Permanently」表示永久重定向,說明請求的資源已經不存在了,需改用新的 URL 再次訪問
「302 Found」表示臨時重定向,說明請求的資源還在,但暫時需要用另一個 URL 來訪問
「301 和 302 都會在響應頭里使用字段 Location,指明后續要跳轉的 URL,瀏覽器會自動重定向新的 URL
「304 Not Modified」不具有跳轉的含義,表示資源未修改,重定向已存在的緩沖文件,也稱緩存重定向,用於緩存控制
4xx
4xx 類狀態碼表示客戶端發送的報文有誤,服務器無法處理,也就是錯誤碼的含義。
「400 Bad Request」表示客戶端請求的報文有錯誤,但只是個籠統的錯誤
「403 Forbidden」表示服務器禁止訪問資源,並不是客戶端的請求出錯
「404 Not Found」表示請求的資源在服務器上不存在或未找到,所以無法提供給客戶端
5xx
4xx 類狀態碼表示客戶端請求報文正確,但是服務器處理時內部發生了錯誤,屬於服務器端的錯誤碼。
「500 Internal Server Error」與 400 類型,是個籠統通用的錯誤碼,服務器發生了什么錯誤,我們並不知道
「501 Not Implemented」表示客戶端請求的功能還不支持,類似 "即將開業,敬請期待" 的意思
「502 Bad Gateway」通常是服務器作為網關或代理時返回的錯誤碼,表示服務器自身工作正常,訪問后端服務器發生了錯誤
「503 Service Unavailable」表示服務器當前很忙,暫時無法響應服務器,類似 "網絡服務正忙,請稍后重試" 的意思
在 HTTP 協議中,正確地理解並應用這些狀態碼不是客戶端或服務器單方的責任,而是雙方共同的責任。客戶端作為請求的發起方,獲取響應報文后,需要通過狀態碼知道請求是否被正確處理,是否要再次發送請求,如果出錯了原因又是什么。這樣才能進行下一步的動作,要么發送新請求,要么改正錯誤重發請求。服務器端作為請求的接收方,也應該很好地運用狀態碼。在處理請求時,選擇最恰當的狀態碼回復客戶端,告知客戶端處理的結果,指示客戶端下一步應該如何行動。特別是在出錯的時候,盡量不要簡單地返 400、500 這樣意思含糊不清的狀態碼。