前言
這篇文章本來是我一年前看《圖解HTTP》做的筆記,但記完後放在資料夾的某個角落一直沒管。前段時間擼專案練手的時候,在狀態碼上碰到了問題,因此又拿了出來翻了翻,同時又在原有的基礎上做了些修改,補上了HTTPs的一些東西。這篇文章主要是對HTTP相對重要的知識的一些概括,想要好好學習HTTP還是需要看《圖解HTTP》或者《HTTP權威指南》,才能構建較為完整的知識體系。最後,你沒有猜錯,我就是傳說中的標題黨,但希望這篇文章對你有用,哪怕是一丁點,2333。
1.HTTP簡述(出自MDN)
超文字傳輸協議(HTTP)是用於傳輸諸如HTML的超媒體文件的應用層協議。它被設計用於Web瀏覽器和Web伺服器之間的通訊,但它也可以用於其他目的。 HTTP遵循經典的客戶端-服務端模型,客戶端開啟一個連線以發出請求,然後等待它收到伺服器端響應。 HTTP是無狀態協議,意味著伺服器不會在兩個請求之間保留任何資料(狀態)。雖然通常基於TCP / IP層,但可以在任何可靠的傳輸層上使用.
2.URL和URI
我們經常會接觸到URL(統一資源定位符),它就是我們用於訪問web的一個字串地址.而URI對我們來講就相對比較陌生了,它的名字叫做統一資源識別符號(URI)。我們來看看它們具體的區別吧:
- URI:uniform resource identifier 統一資源識別符號,一種資源的標識,它是一種抽象的資源標識,即可以是相對的,也可以是絕對的。
- URL:uniform resource location 統一資源定位符,同時一種資源的標識,但指明瞭如何定位Locate這個資源。因為它指明瞭定位的資訊,所以必須是絕對的。
(我們平時所說的相對地址,其實只是相對於另一個絕對地址而言的)
2.1 URL
URL的基本格式如下:
schema://host[:port#]/path/.../[?query-string][#anchor]
複製程式碼
格式 | 意義 |
---|---|
scheme | 指定低層使用的協議(例如:http, https, ftp)。 |
host | HTTP伺服器的IP地址或者域名。 |
port# | HTTP伺服器的預設埠是80,這種情況下埠號可以省略。如果使用了別的埠,必須指明。 |
path | 訪問資源的路徑。 |
query-string | 傳送給http伺服器的資料。 |
anchor- | 錨 |
3.HTTP報文
3.1 HTTP報文格式
HTTP的報文格式主要分為報文首部和報文主體:
其中的空行用於區分報文首部和報文主體內容,是由一個回車符和一個換行符組成的。
無論是請求報文還是響應報文都需要有報文首部,而報文主體有些請求報文是沒有的。而請求報文的一般格式如下:
而響應報文的格式是這樣的:
下面是谷歌瀏覽器的HTTP報文內容,其中request headers描述了請求報文頭部的內容,response headers描述了響應報文頭部的內容:
其中最常見的屬性如下:
- URL, 即http訪問的地址
- request method, 報文的請求方式
- status code, 狀態碼以及狀態短語
- Accept Encoding, 內容編碼
- Connection, 連線方式
- Cookie, 新增的cookie內容
- Host, 目標主機
- User-Agent, 客戶端瀏覽器的相關資訊
- Set-Cookie, 指定想要在Cookie中儲存的內容
接下來就聊一聊這些屬性的作用
3.2 HTTP請求方式(request method)——GET and POST
傳送HTTP的方式有很多,但最常用的還是POST和GET。
-
GET:GET方法可以用來請求訪問已經被URL識別的資源。指定的資源經過服務端解析後返回響應的內容。簡單來說,就是請求的資源是文字的話,那麼就保持原樣返回.
-
POST:POST方法可以用來傳輸實體的主體。
這兩者的區別主要如下:
- 使用目標不同
POST與GET都用於獲取資訊,但是GET方式僅僅是查詢,並不對伺服器上的內容產生任何作用結果;每次GET的內容都是相同的。POST則常用於傳送一定的內容進行某些修改操作。
- 大小不同
由於不同的瀏覽器對URL的長度大小有一定的字元限制,因此由於GET方式放在URL的首部中,自然也跟著首先,但是具體的大小要依瀏覽器而定。POST方式則是把內容放在報文內容中,因此只要報文的內容沒有限制,它的大小就沒有限制。
- 安全性不同
上面也說了GET是直接新增到URL後面的,直接就可以在URL中看到內容。而POST是放在報文內部的,使用者無法直接看到。
總的來說,GET用於獲取某個內容,POST用於提交某種資料請求,從使用場景來看,一般使用者註冊的內容是私密的,應該使用POST方式來保持私密,而當需要查詢某個內容時,需要快速響應,則使用GET。
3.3 status code狀態碼
狀態碼通常就是伺服器端對客戶端說的話,分類如下:
狀態碼 | 含義 |
---|---|
1** | 伺服器收到請求,需要請求者繼續執行操作 |
2** | 成功,操作被成功接收並處理 |
3** | 重新定向,需要進一步的操作以完成請求 |
4** | 客戶端錯誤,請求包含語法錯誤或無法完成請求 |
5** | 伺服器錯誤,伺服器在處理請求的過程中發生了錯誤 |
常見的狀態碼:
- 200 通常的成功 OK
GET:請求的對應資源會作為響應返回。響應將包含描述或操作的結果。
POST:返回處理對應請求的結果。
- 204 成功處理請求,沒有返回任何內容 No Content
表示伺服器接收到的請求已經處理完畢,但是伺服器不需要返回響應。比如,客戶端是瀏覽器的話,那麼瀏覽器顯示的頁面不會發生更新。
- 206 Partial Content
成功處理了部分GET請求
- 301 Moved Permanently
請求的網頁已永久移動到新位置,永久性重定向
- 302 Found
網站臨時性重定向,暫時不能訪問(備案、被查)
- 303 See Other
該狀態碼錶示由於請求對應的資源存在另一個URI,並指定必須使用GET方法定向獲取請求的資源。和302不同的是,302是不會改變上次的請求方法
- 304 Not Modified
訪問不了,並返回和上次一樣的話,表示資源未被修改過,還是和上次訪問時一樣。
- 307 Temporary Redirect
臨時重定向,和302、303類似,不同的是,不會指定客戶端要用什麼樣的方法請求,
- 400 Bad Request
表示客戶端中存在語法錯誤,導致伺服器無法理解該請求。客戶端需要修改請求的內容後再次傳送請求。
- 401 Unauthorized
即使用者沒有必要的憑據。該狀態碼錶示當前請求需要使用者驗證。
- 403 Forbidden
伺服器已經理解請求,但是拒絕執行它。
- 404 Not Found
伺服器找不到請求的網頁。
- 500 Internal Server Error
伺服器遇到錯誤,無法完成請求。
- 503 Service Unavailable
由於臨時的伺服器維護或者過載,伺服器當前無法處理請求。這個狀況是暫時的.
3.4 內容編碼 Accept Encoding
由於有些報文的內容會過大,為了減少傳輸時間,HTTP會採取一些壓縮的措施,例如上面的報文資訊中,Accept-Encoding就定義了內容編碼的格式gzip。
總的來說內容編碼的格式有以下幾種:
- gzip:GNU壓縮格式
- compress:UNIX系統的標準壓縮格式
- deflate:是一種同時使用了LZ77和哈夫曼編碼的無損失壓縮格式
- identity:不進行壓縮
3.5 持久化——connection
正常傳送HTTP時,我們需要建立TCP的連線,然後再傳送報文:
如果每次都要傳送HTTP報文都需要經歷上面的拿過過程,無疑將會耗費很多時間在建立和斷開連線的過程中,因此HTTP使用了connection屬性,用於指定連線的方式,噹噹設定成keep-alive時,就會建立一條持久化的連線。這樣就不需要每次都建立連線在中斷連線:
(HTTP1.1中connection預設開啟keep-alive)
3.6 無狀態的HTTP——cookie
由於HTTP是一種無狀態的協議,這是由於Web伺服器要面對很多瀏覽器的併發訪問,為了提高Web伺服器對併發訪問的處理能力,在設計HTTP協議時規定Web伺服器傳送HTTP應答報文和文件時,不儲存發出請求的Web瀏覽器程式的任何狀態資訊,從而減輕伺服器端的負載,同時無狀態也減小了HTTP請求的開銷。
但當有些場景需要時刻記住使用者的資訊時,無狀態很明顯不能滿足需求,因此HTTP提供了cookie來解決這個問題,cookie技術通過在請求和相應報文中寫入cookie資訊來控制客戶端的狀態。cookie會根據從服務端傳送的相應報文內的一個叫做set-cookie的首部欄位資訊,通知客戶端儲存cookie。當下次客戶端再往伺服器傳送請求的時候,客戶端會自動在請求頭加入cookie值後傳送出去。在沒有cookie狀態下的請求:
當存有cookie後的請求:
簡單來說Cookie是一種由伺服器端確定,並儲存在客戶端瀏覽器中的內容。這樣就與每次都去新增使用者的資訊,請求會自動新增cookie中對應的內容。
(關於瀏覽器端的資料儲存感興趣的可以看下這篇文章::聊一聊常見的瀏覽器端資料儲存方案)
3.7 範圍請求
在一些場景下,我們在使用HTTP報文請求一些很大的圖片時,載入過程往往會很慢。(比如一些攝影網站)這時候我們就會發現一些圖片是一塊一塊載入的。這是應為設定了HTTP請求的長度,從而分塊的載入資源。在請求報文中使用Range屬性,在響應報文中使用Content-Type屬性都可以進行指定一定自己的HTTP請求。
3.8 報文首部總結
(圖轉自:http://www.cnblogs.com/xing901022/p/4311987.html)
4.HTTP方法
HTTP 支援幾種不同的請求命令,這些命令被稱為 HTTP 方法(HTTP method)。每
條 HTTP 請求報文都包含一個方法。這個方法會告訴伺服器要執行什麼動作(獲取
一個 Web 頁面、執行一個閘道器程式、刪除一個檔案等)。下表是一些常見的HTTP方法:
HTTP方法 | 描述 |
---|---|
GET | 從伺服器向客戶端傳送命名資源 |
PUT | 將來自客戶端的資料儲存到一個命名的伺服器資源中去 |
DELETE | 從伺服器中刪除命名資源 |
POST | 將客戶端資料傳送到一個伺服器閘道器應用程式 |
HEAD | 僅傳送命名資源響應中的 HTTP 首部 |
(GET和POST已在上面討論過了,這裡就不在討論了)
4.1、PUT傳輸檔案
PUT方法用於傳輸檔案,就像FTP協議的翁建上傳一樣,要求在請求報文的主題中包含檔案內容,然後儲存到請求URI指定的位置。由於PUT方法不帶驗證機制,任何人都可以任何人都可以上傳檔案,存在安全性問題,因此一般的web網站不適用該方法。
4.2、DELETE刪除檔案
DELETE方法用來刪除檔案,是與put相反的方法,DELETE方法按照請求url刪除指定的資源。其本質和PUT方法一樣不帶驗證機制,所以建議少用DELETE方法。
4.3、HEAD獲取報文首部
HEAD和GET方法一樣,只是不返回報文主體部分,通常用於確認url的有效性及資源更新的日期時間等。
5.HTTPS
5.1 什麼是HTTPS
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單來說就是是HTTP的安全版本,即在HTTP下加入SSL層,HTTPS的安全基石是SSL,因此加密的詳細內容就需要SSL。 它現在已經被廣泛應用,比如GitHub,支付寶,掘金等。
5.2 為什麼需要HTTPS
這是由於HTTP有這麼幾個缺點:
- 傳輸的時候使用明文,這顯然會被不法者擷取幹一些見不得人的勾當。
- 沒有認證機制,這樣我們就可以偽造一些HTTP訪問,這顯然會造成一些困擾。比如Jmeter就是典型的例子,偽造一大堆的HTTP URL然後壓力測試,這也就是DOS攻擊的一種。
- 無法驗證報文的完整性,比如一個HTTP的報文已經被不法者擷取並且篡改,而伺服器端卻無法驗證。
5.3 HTTP 與 HTTPS 的區別
正是由於以上這些缺點,HTTPS作出了以下一些改變:
- HTTP 是明文傳輸,HTTPS 通過 SSLTLS 進行了加密;
- HTTP 的埠號是 80,HTTPS 是 443;
- HTTPS 需要到 CA 申請證書,一般免費證書很少,需要交費;
- -HTTP 的連線很簡單,是無狀態的。而 HTTPS 協議則是由 SSL+HTTP; 協議構建的可進行加密傳輸、身份認證的網路協議,比 HTTP 協議安全
5.4 HTTPS的缺陷
可以說HTTPS相對於HTTP就是套上了黃金甲的聖鬥士,變了身的奧特曼,沉睡了的毛利小五郎,不僅僅提升了安全,還提升了逼格。但HTTPS也有一些缺陷:
- 通訊的速度變慢,由於需要加密,一個握手就多了好幾個往返;
- 對使用者的機器負載的增加。(說出來你們可能不信,我們學校一到晚上,用HTTPS協議的網站基本上都上不了)
6. HTTP認證
有一些網站需要使用者的登入從而獲取使用者的個人資訊來進行接下來的操作,因此需要隨時知道這些訊息,但是肯定不能每次都讓使用者輸入使用者密碼,這樣會讓使用者感覺很不爽,因此HTTP也自帶了認證的功能,認證方式主要如下:
6.1 BASIC認證
其中BASIC認證是最簡單的認證,大致過程如下:
- 客戶端訪問某URL。
- 伺服器端返回401狀態碼,提示使用者輸入使用者名稱密碼。
- 使用者輸入使用者名稱密碼,通過BASE64編碼傳輸。
- 伺服器通過認證,返回狀態碼200
但它有以下缺陷:
- 僅僅通過BASE64編碼,其實還是屬於明文傳輸,安全性不高
- 有的瀏覽器不支援登出
6.2 DIGEST認證
正是由於BASIC認證存在弱點,因此從HTTP/1.1起就有了DIGEST認證,DIGEST認證同樣使用質詢/響應的方式,但不會像BASIC認證那樣直接明文傳送密碼。
6.3 SSL認證(比較常見)
SSL客戶端認證是藉由HTTPS的客戶端證書完成認證的方式。憑藉客戶端證書認證,伺服器可確認訪問是否來自已登入的客戶端。
SSL客戶端認證的步驟:
- 伺服器接收到需要認證資源的請求時,伺服器會傳送CertificateRequest報文,要求客戶端提供客戶端證書。
- 客戶端將客戶端證書資訊以Client Certificate報文方式傳送給伺服器。
- 伺服器驗證客戶端證書驗證通過後才能領取證書內客戶端的公開金鑰,然後開始HTTPS加密通訊。
像支付寶,網銀之類對安全要求很高的網站,在登入時,都需要下載一個數字認證,這個數字認證就屬於一種SSL客戶端的驗證。但它的缺點也很明顯,需要手動下載,對於現在越來越懶的網民們來講會感覺很麻煩(包括我)
6.4 表單認證(最常用的)
最後一種認證方式是最常見的,我們可以通過cookie或session來進行認證。
Session管理和Cookie應用的結合
我前面提到過,HTTP是無狀態協議,無法實現狀態管理,因此有了cookie。我們就可以使用Cookie來管理Session(會話),以彌補HTTP協議中不存在的狀態管理功能。
認證步驟:
- 客戶端把使用者的ID和密碼等相關資訊放入報文的實體部分,然後通常以POST請求的方式傳送給伺服器。
- 伺服器會發放用以識別使用者的Session ID。通過驗證從客戶端傳送過來的登入資訊進行身份認證,將使用者的認證狀態和Session ID繫結後記錄在伺服器端。
- 客戶端接收到Session ID後,會將其作為Cookie儲存在本地。下次向伺服器傳送請求時,瀏覽器自動傳送Cookie,Session ID會隨之傳送到伺服器。服務端通過驗證接收到的Session ID識別使用者和其認證狀態,然後使用者就能執行特定的操作了。
參考資料:
- 《圖解HTTP》
- https://juejin.im/post/59e4c02151882578d02f4aca
- http://www.cnblogs.com/xing901022/p/4309840.html