HTTP協議理解與應用總結

HTTP 工做原理

HTTP 協議採用請求/響應模型。客戶端向服務器發送一個請求報文,服務器以一個狀態做爲響應。css

如下是 HTTP 請求/響應的步驟:html

● 客戶端鏈接到web服務器:HTTP 客戶端與web服務器創建一個 TCP 鏈接;node

● 客戶端向服務器發起 HTTP 請求:經過已創建的TCP 鏈接,客戶端向服務器發送一個請求報文;nginx

● 服務器接收 HTTP 請求並返回 HTTP 響應:服務器解析請求,定位請求資源,服務器將資源副本寫到 TCP 鏈接,由客戶端讀取;web

● 釋放 TCP 鏈接:若connection 模式爲close,則服務器主動關閉TCP 鏈接,客戶端被動關閉鏈接,釋放TCP 鏈接;若connection 模式爲keepalive,則該鏈接會保持一段時間,在該時間內能夠繼續接收請求;算法

● 客戶端瀏覽器解析HTML內容:客戶端將服務器響應的 html 文本解析並顯示;數據庫

例如:在瀏覽器地址欄鍵入URL,按下回車以後會經歷如下流程:json

一、瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;windows

二、解析出 IP 地址後,根據該 IP 地址和默認端口 80,和服務器創建 TCP 鏈接;後端

三、瀏覽器發出讀取文件(URL 中域名後面部分對應的文件)的HTTP 請求,該請求報文做爲 TCP 三次握手的第三個報文的數據發送給服務器;

四、服務器對瀏覽器請求做出響應,並把對應的 html 文本發送給瀏覽器;

五、釋放 TCP 鏈接;

六、瀏覽器將該 html 文本並顯示內容;

Request & Response

Request格式

<request-line> 好比:GET /api/index.json HTTP/1.1
<headers> 好比:Accept: */*; User-Agent: Mozilla/4.0;……
<blank line>
[<request-body>] 好比:id=1&timestamp=xxxxxx

Response格式

<status-line> 好比:HTTP/1.1 200 OK
<headers> 好比:Content-Type: application/json;……
<blank line>
[<response-body>] 好比:{"id":1,"username":"testuser"}

Status Code

http的狀態碼有將近60個,我這裏主要記錄一些常見的非正常狀況下產生的狀態碼,在日常應用中或多或少會碰到,有助於咱們去理解和發現問題。

206 – 斷點下載時用到,客戶端請求了一部份內容,服務器成功把這部份內容返回給它,這時候就是用這個狀態。

301 – 永久跳轉,原地址不存在了,url被指向到另外一個地址。這個主要是搜索引擎相關,影響爬蟲的檢索行爲。

302 – 臨時跳轉,服務器會返回一個新的url給客戶端,客戶端能夠繼續訪問這個url來獲取內容。

304 – 資源沒有改變,客戶端可使用本地緩存的內容,常見於靜態內容訪問。

413 – 請求實體太大。常見的狀況是上傳大文件,但超出了服務器(好比nginx)限制。或者請求頭或請求體超出了後端的server(好比tomcat)的設置(好比當前域名下cookie太多,超出了請求頭限制)

416 – 跟斷點續傳有關,客戶端請求的範圍超出了服務器上文件大小。

500 – 服務器內部錯誤,不能返回正常的結果。好比最多見的應用拋出空指針異常未進行處理。

502 – 網關錯誤。常見的狀況是反向代理後端的服務器(好比resin或tomcat)沒有啓動。

503 – 服務不可用。好比服務器負載過高或者服務器已經中止服務。

504 – 網關超時。好比請求時長超出了服務器的響應時間限制。

Headers

http headers分爲請求頭(Request Header)和響應頭(Response Header)兩類。下面是咱們常常用到的一些header.

1.緩存控制

在互聯網站的應用中,緩存幾乎無處不在,在基於http的服務中,咱們也能夠對一些不常改變的內容在客戶端進行緩存,這樣在屢次訪問中能夠複用緩存內容,加快訪問速度,提高用戶體驗。http的協議裏規定了一些用於緩存控制的http消息頭:

Cache-Control(HTTP/1.1)/Pragma(HTTP/1.0):指 示客戶端是否進行緩存以及緩存的時間是多長。默認值是private,也就是把內容緩存在用戶私有空間。好比:Cache-Control:max- age=86400,must-revalidate,這是告訴客戶端所請求的資源緩存一天(max-age單位是秒,相對時間),過時以後必須進行從新 檢驗。

Expires:指定客戶端(若是不強制刷新的話)在多長時間裏能夠不向服務器發請求,直接讀本地緩存。

注意:

  1. 優先級:Cache-Control > Expires;

  2. 詳細參數說明:http://condor.depaul.edu/dmumaugh/readings/handouts/SE435/HTTP/node24.html

  3. 不一樣瀏覽器的不一樣行爲(刷新,後退,地址欄回車等)在實現上可能有差別;

Last-Modified/If-Modified-Since:Last-Modified是服務器端返回 給客戶端的資源最後修改時間戳,這樣,客戶端在下次請求時(好比強制刷新)會帶上If-Modified-Since參數來校驗資源是否有更新,沒有更新 的話服務器就返回304狀態碼,客戶端直接取本地緩存的資源。這個時候只有請求開銷,沒有網絡傳輸開銷。注意:時間戳必須是格林威治(GMT)時間,比 如:Last-Modified:Sat, 19 Oct 2013 09:20:15 GMT

ETag/If-None-Match:ETag是根據文件屬性經過必定算法生成的資源標識,也是用來肯定客戶 端請求的資源是否有更新。若是服務器返回了一個ETag值給客戶端,那麼下次客戶端請求時會帶上If-None-Match參數來校驗資源是否更新,沒有 更新的就返回304狀態碼。(效果基本等同於Last-Modified)

注意:

  1. ETag須要計算,對於計算資源緊張的服務器來講是一種消耗,因此有些網站直接不使用ETag;

  2. 若是服務器在負載均衡後 面,同一個資源的請求可能分發到不一樣的後端機器上,因爲ETag的計算依賴於文件屬性,不一樣機器上內容相同的文件可能生成的ETag不一樣,這樣就可能使本 來內容沒變的文件經過ETag校驗失敗。這裏有兩種解決方案:一是etag計算不依賴於本地機器,好比直接算文件內容的md5值;二是在負載均衡器上把相 同的url請求分發到同一臺後端機器。

在咱們的實際業務場景下,http的緩存具備很是大的用途,下面列舉一些:

  1. 充分利用客戶端的資源,好比一些客戶端須要頻繁訪問的靜態文件,像LOGO,廣告圖等,徹底能夠緩存在客戶端本地。這樣能夠減小網絡請求,加快客戶端展現,還能減小服務器請求的壓力。

  2. 咱們的一些靜態內容,好比新聞,博客等,在被搜索引擎爬蟲抓取的時候,經過控制緩存參數,就能夠減小爬蟲的抓取頻率,減小沒必要要的資源浪費。

  3. 若是咱們的靜態資源使用了CDN,那麼設置了http緩存就能夠在CDN節點上保存一份文件,減小CDN的回源次數,減小網絡延時和源站服務器壓力。

2.斷點請求

Accept-Ranges:服務端支持斷點下載時會返回這個響應頭給客戶端,當客戶端知道這個之後就能夠發送斷點請求了。

Content-Length:響應信息的長度,告訴客戶端當前請求返回了多少數據。這裏要注意一下,用head方法提交請求時不會返回具體數據,可是這個Content-Length會返回完整數據的大小。

Range/Content-Range:客戶端請求時提交名爲Range的header,告訴服務器本身要請 求哪部分的數據。好比:Range: bytes=0-1023表示請求第0到1023個字節.而後服務器返回這1024個字節的內容給客戶端,響應頭中會帶上Content-Range。 即:Content-Range: bytes 0-1023/4096,這個4096就是文件總大小。客戶端下次請求能夠從第1024個字節處開始,Range: bytes=1024-xxxx

3.編碼

Accept-Encoding/Content-Encoding:前者是客戶端支 持接收的消息編碼類型。默認是identity,可選值有gzip,compress等。後者是服務器端響應信息的內容編碼類型,經常使用的就是壓縮。壓縮的 好處顯而易見,能夠大大減小網絡傳輸的開銷,相對於服務器端壓縮產生的cpu消耗,網絡傳輸的減小顯然更實在。常見形式:Content- Encoding: gzip,deflate,compress.一般咱們對html,js,css,xml,json之類的響應結果能夠進行壓縮傳輸。

Transfer-Encoding:response header.響應消息的傳輸編碼類型,規定了網絡傳輸的形式。通常都是下面這種形式:Transfer-Encoding: chunked。當服務器產生動態內容,不知道響應信息的具體長度時,能夠經過這個指定分塊進行傳輸,處理多少數據就返回多少數據,這樣不用等到數據都準 備好了一次性返回。結合上面的內容編碼,好比gzip,能夠分塊壓縮並進行傳輸。另外,請注意,在使用這種編碼傳輸時,咱們是看不到Content- Length的,由於內容尚未徹底生成。

4.其餘

X-Forward-For:request header. 用來標識用戶的真實ip,特別是經過代理(正向或反向)訪問服務器或是服務器在負載均衡設備後面的狀況。格式:X-forward-For: client,proxy1,proxy2,…最左邊的是最接近客戶端的ip。

User-Agent:request header.服務器用來識別客戶端基本信息的請求頭。通常這個在識別搜索爬蟲的時候有用,某些場景下也能夠用這個來作一些客戶端的統計。

Referer:request header.客戶端訪問服務器時,這個Referer來指定請求來源,好比是從哪一個網站連接過來的,咱們在一些統計中會常常用到這個。另外,還有一個重 要的用途就是在須要資源防盜鏈的場景中來過濾非法的請求來源(可是,這個referer是客戶端能夠僞造的)。

Location:response header.在301/302狀態碼的響應頭中,都會帶上這個Location頭,來指示客戶端用新的地址去訪問須要的資源。

Connection:request/response header.在http/1.1中,客戶端和服務端默認都是保持鏈接的,也就是Connection: keep-alive.若是任何一方不想保持鏈接,均可以把這個值設置爲close.默認狀況下,客戶端和服務端會保持一個長鏈接,這樣客戶端就能夠用這 個鏈接發送屢次http請求,減小頻繁建立鏈接帶來的消耗。對於這個參數,在服務端可能要作更多的設置,好比鏈接keep-alive的時間,服務器內核 的一些網絡參數設置(針對tcp)。

Session和Cookie

http請求是無狀態的請求,可是在咱們的互聯網應用中,常常須要標識用戶狀態信息來完成一些交互性的操做,好比用戶認證要記錄用戶登陸狀態,購物車應用要記住用戶選擇的商品,廣告投放應用要記錄用戶的歷史瀏覽行爲等等。這裏就會用到session和cookie了。

session:是指http請求-響應的過程當中客戶端與服務器端的交互狀態,這些信息被保存在服務器端,好比內存,數據庫等。每一個session都有一個惟一標識,由服務器生成,這個標識也要在客戶端進行保存,這樣客戶端在下次請求時能夠帶上這個標識,方便服務器判斷客戶端的狀態。

客戶端對session的支持:

  1. 經過cookie保存session id,在請求時發送給服務器。

  2. 經過url的參數攜帶session id與服務器通訊。

  3. 經過表單的隱藏字段攜帶session id與服務器通訊。

session共享的問題:

在分佈式應用中,咱們的http server通常都架在反向代理或是負載均衡設備後面,這就會面臨一個session共享的問題。也就是同一個用戶的多個請求可能被分發到多個不一樣的機 器,若是咱們把session保存在機器本地內存中的話,就沒法在多個機器間共享用戶的session。這個問題,通常來講,咱們能夠有兩種方式來解決:

  1. 把session存放到分佈式的內存(eg:memcached)或是集中式存儲中(eg:database)。

  2. 在反向代理或負載均衡設備上把相同用戶的請求分發到同一臺機器(這裏要處理好機器宕機後請求從新分配的問題)。

cookie:在客戶端保持狀態化信息,每一個cookie內容都屬於特定的域(domain)和路徑(path),出於安全考慮,不一樣域或路徑下的cookie不能共享。

會話cookie:沒有指定過時時間,保存在內存,瀏覽器關閉後就失效。

持久cookie:指定了過時時間,保存在瀏覽器本地。

詳細內容能夠參考:http://en.wikipedia.org/wiki/HTTP_cookie

須要注意的是cookie會存在一些安全方面的問題。

在這裏我只是總結了本身在工做中遇到的與http協議相關的一些內容的理解,http協議還有不少須要挖掘的東西,也須要不斷去探索,對http協議的理解將會給咱們的開發應用帶來很大的便利。

最後,推薦兩個很NB的http調試工具:fiddler(windows)和charles(mac)有http代理功能,對於不是基於瀏覽器的http應用(好比mobile app),能夠用這兩個工具來監控http請求。

相關文章
相關標籤/搜索