HTTP協議相關

Http協議


(一)從輸入URL到頁面加載發生了什麼

1. 在瀏覽器中輸入URL

kwLPS.md.png

2. 瀏覽器經過域名去找對應的IP

  • 瀏覽器緩存-瀏覽器時不時會緩存DNS記錄,OS並無明確指明瀏覽器每條記錄的生命週期是多長,因此瀏覽器按期的緩存DNS記錄(大概2-30分鐘不等)。下圖爲chrome瀏覽器緩存記錄(chrome://net-internals#dns

kwKTH.md.png

  • 系統緩存-若是緩存中沒有,就去調用gethostbyname庫函數(操做系統不一樣函數也不一樣)進行查詢。函數在試圖進行DNS解析以前首先檢查域名是否在本地Hosts文件裏,Hosts文件的位置,不一樣的操做系統也有所不一樣。
  • 路由緩存-若是gethostbyname沒有這個域名的緩存記錄,也沒有在hosts裏找到,它將會向DNS服務器發送一條DNS查詢請求。DNS服務器是由網絡通訊棧提供的,一般是本地路由器或者ISP的緩存DNS服務器。
  • ISP DNS緩存-查詢本地網絡提供商的DNS服務器。
  • 遞歸查找

3.瀏覽器向服務器發送一個HTTP請求

因爲srs.testpub.cn頁面是動態的,因此瀏覽器不會從緩存裏讀頁面的內容,瀏覽器會向服務器發送HTTP請求,請求可能以下所示:php

GET http://facebook.com/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, [...]
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; [...]
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: facebook.com
Cookie: datr=1265876274-[...]; locale=en_US; lsd=WW[...]; c_user=2101[...]

GET請求的URL是「http://facebook.com」,瀏覽器經過(User-Agent header)來代表本身是誰,以及本身接受什麼樣類型的響應(Accept and Accept-Encoding headers)。Connection header告訴服務器不要關閉TCP鏈接以便爲後來請求所重用。css

請求中還會帶上cookie,cookie就是一些鍵值對,能夠用來保持不一樣頁面請求間的狀態。所以cookie能夠儲存登陸的用戶的名稱,服務器爲用戶分配的惟一密碼以及一些用戶設置信息等。cookie是存在客戶端的,每次客戶端向服務器發送請求都會帶上cookie。html

4.facebook服務器發出重定向響應

服務器給出以下響應:前端

HTTP/1.1 301 Moved Permanently
Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,
      pre-check=0
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Location: http://www.facebook.com/
P3P: CP="DSP LAW"
Pragma: no-cache
Set-Cookie: made_write_conn=deleted; expires=Thu, 12-Feb-2009 05:09:50 GMT;
      path=/; domain=.facebook.com; httponly
Content-Type: text/html; charset=utf-8
X-Cnection: close
Date: Fri, 12 Feb 2010 05:09:51 GMT
Content-Length: 0

這告訴瀏覽器應該訪問的是「http://www.facebook.com」而不是「http://facebook.com/」。而之因此重定向的緣由,就是爲了增長域名的權重,在這裏即增長了www.facebook.com域名的權重。nginx

5.瀏覽器跟隨重定向

瀏覽器向「http://www.facebook.com/」發送請求web

GET http://www.facebook.com/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, [...]
Accept-Language: en-US
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; [...]
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Cookie: lsd=XW[...]; c_user=21[...]; x-referer=[...]
Host: www.facebook.com

6. 瀏覽器開始處理請求

瀏覽器開始處理請求並返回響應。ajax

  • Web服務器軟件

web服務器軟件,如IIS(
Internet Information Services-互聯網信息服務)或Apache接收到HTTP請求,決定哪一個處理器來處理該請求。一個請求處理器是一個程序(可由ASP.NET、PHP、Ruby或其餘語言編寫)用來讀請求並生成響應的HTML。最簡單的例子,一個請求處理器可被儲存在一個文件結構中,該文件結構映射URL結構,好比URL:http://example.com/folder1/page1.aspx對應文件/httpdocs/folder1/page1.aspx。web服務器軟件可配置,所以URL可由被手動映射到請求處理器,所以公page1.aspx的公有URL可由是http://example.com/folder1/page1chrome

  • 請求處理器

請求處理器讀取請求,請求參數,cookie。讀取過程當中有可能更新某些數據到服務器端。而後,請求處理器會生成一個HTML格式的響應。跨域

7.服務器返回HTML響應

HTTP/1.1 200 OK
Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,
    pre-check=0
Expires: Sat, 01 Jan 2000 00:00:00 GMT
P3P: CP="DSP LAW"
Pragma: no-cache
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
X-Cnection: close
Transfer-Encoding: chunked
Date: Fri, 12 Feb 2010 09:05:55 GMT

Content-Encoding header告訴瀏覽器響應的body是被gzip給壓縮過的,將body解壓以後,本來的HTML就顯示出來了。瀏覽器

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en" id="facebook" class=" no_js">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-language" content="en" />
...

除了解壓方式以外,headers還會告訴瀏覽器如何緩存頁面等,總之headers很重要。

8.瀏覽器開始渲染HTML

9.瀏覽器發送請求去獲取HTML中的一些內嵌對象

瀏覽器會開始獲取頁面上的一些引用資源,好比:

Images
http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif
http://static.ak.fbcdn.net/rsrc.php/zBS5C/hash/7hwy7at6.gif
…
CSS style sheets
http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css
http://static.ak.fbcdn.net/rsrc.php/zANE1/hash/cvtutcee.css
…
JavaScript files
http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js
http://static.ak.fbcdn.net/rsrc.php/z6R9L/hash/cq2lgbs8.js
…

每個請求都是跟上面的GET請求差很少,都要通過dns解析等一系統過程。
不過靜態文件是能夠被瀏覽器緩存的,因此有一些靜態文件瀏覽器可能直接從緩存裏讀取,而不須要去服務器端讀。能夠經過chrome://cache/來查看瀏覽器緩存。
lHtm2.md.png

10.瀏覽器發送異步的AJAX請求

AJAX = 異步Javascript和XML。
AJAX是一種用於建立快速動態網頁的技術。經過在後臺與服務器進行少許的數據交換,AJAX可使網頁實現異步更新。這意味着能夠在不從新加載整個網頁的狀況下,對網頁的某部分進行更新。


(二)HTTP協議概述

HTTP是一種可以獲取如HTML這樣網絡資源的協議。它是Web上數據交換的基礎,是一種client-server協議,也就是說請求一般是由像瀏覽器這樣的接收方發起的。一個完整的web文檔是由不一樣的子文檔從新組合而成的,像是文本、佈局描述、圖片、視頻、腳本等等。

客戶端和服務器端經過交換各類的信息(與數據流正好相反)來進行交互。一般由像瀏覽器這樣的客戶端發出的消息叫requests,被服務器端迴應的消息就叫作responses。

HTTP被設計於20世紀90年代,是一種可擴展性的協議,他是應用層的協議,雖然理論上能夠經過任何可靠的傳輸協議來發送,可是仍是經過TCP或者TLS-加密的TCP鏈接來發送。由於由很好的擴展性,時至今日不只被用來傳輸超文本文檔,還用來傳輸圖片、視頻或向服務器發送如HTML表單這樣的信息。HTTP還能夠根據網頁的需求,來獲取部分web文檔的內容來更新網頁。

HTTP協議的參與者

HTTP是一個client-server協議:請求經過一個實體被髮出,實體也就是用戶代理。大多數狀況下,這個用戶代理都是指瀏覽器,固然它也多是任何東西,好比一個爬取網頁來生成河維護搜素引擎索引的機器。

每個發送到服務器的請求,都會被服務器處理而且返回一個消息,也就是response。在client與server之間,還有許許多多的被稱爲proxies的實體,他們的做用與表現各不相同,好比有些是網關,還有些是caches等。
lXg9d.md.png
實際上,在一個瀏覽器和處理請求的服務器之間,還有計算機、路由器、調制解調器等等許多實體。因爲Web的層次設計,那些在網絡層和傳輸層都不可見了。HTTP是在最上層應用層中的,雖然下面的層次對分析網絡問題很是重要,可是對HTTP的描述老說,這些大多數都是不相干的。

1.客戶端:user-agent

嚴格意義來講,user-agent就是任何可以表現出用戶通常行爲的工具。但實際上,這個角色一般都是由瀏覽器來扮演的。

簡單來講user-agent就是來者何人,留下姓名的意思。

對於發起請求來講,瀏覽器老是做爲發起一個請求的實體,而永遠不是服務器(雖然一些機制已經可以模擬服務器發起請求的消息了)。

要渲染出一個網頁,瀏覽器首先要發送第一個請求來獲取這個頁面的HTML文檔,再解析它並根據文檔中的資源信息發送其餘的請求來獲取腳本信息,或者CSS來進行頁面佈局渲染,還有一些其餘的頁面資源(如圖片和視頻等)。而後,它把這些資源結合到一塊兒,展示出來一個完整的文檔,也就是網頁。打開一個網頁後,瀏覽器還能夠根據腳本內容來獲取更多的資源來更新網頁。

一個網頁就是一個超文本文檔,也就是說由一部分顯示的文本多是連接,啓動它(一般是鼠標的點擊)就能夠獲取一個新的網頁。網頁使得用戶能夠控制它的user-agent來導航Web。瀏覽器來負責翻譯HTTP請求的命令,並翻譯HTTP的返回消息讓用戶能明白返回消息的內容。

2.Web服務端

在上述通訊過程的另外一端,就是一個Web Server來服務並提供客戶端請求的文檔。Server至少虛擬意義上:它能夠是許多共同分擔負載(負載平衡)的一組服務器組成的計算機羣,也能夠是一種複雜的軟件,經過向其餘計算機發起請求來獲取部分或所有資源的軟件。

Server再也不只是一個單獨的機器,它能夠是在同一個機器上裝載的許多服務之一。在HTTP/1.1和Host頭部中,它們甚至能夠共享同一個IP地址。

3.Proxies

在瀏覽器和服務器之間,有許多計算機和其餘設備轉發了HTTP的消息。由於Web棧層次結果的緣由,它們大多數都出如今傳輸層、網絡層和物理層上,對於HTTP的應用層來講就是透明的(雖然它們可能會對應用的性能有重要影響)。而還有一部分表如今應用層上的,就叫作proxies(中文翻譯爲代理)了。Proxies既能夠表現得透明,又能夠不透明(看請求是否經過它們),主要表如今這幾個功能上:

  • 緩存(能夠是公開的或私有的,像瀏覽器的緩存)
  • 過濾(像反病毒掃描,家長監護)
  • 負載均衡,讓多個服務器服務不一樣的請求
  • 對不一樣資源的權限控制
  • 登陸,容許存儲歷史信息

HTTP的基本性質

HTTP是簡單的

即使在HTTP/2中把HTTP消息封裝到了frames中,HTTP大致上仍是被設計成可讀的並且簡單的。HTTP的消息可以讓人讀懂且明白它的意思,還容許見得測試,放低了門檻,更有利於新來者瞭解。

HTTP是可擴展的

在HTTP/1中就出現了,HTTP Headers讓協議擴展變得很是容易。只要服務端和客戶端在新的headers上語義達成一致,新的功能就能夠輕鬆地被加進來。

HTTP是無狀態的,有會話的

HTTP是無狀態的:在同一個鏈接中,兩個成功執行的請求之間是沒有關係的。
而HTTP的核心是無狀態的,cookies的使用能夠建立有狀態的會話。

HTTP和鏈接

一個鏈接是由傳輸層來控制的,基本不屬於HTTP的範圍內。然而HTTP並不須要下面傳輸層的協議是面向鏈接的,它只須要它是可靠的,就是說不能丟失消息(至少沒有錯誤)。在因特網兩個最經常使用的傳輸層協議中,TCP是可靠的,而UDP不是。所以,HTTP依賴於TCP進行消息傳遞,雖然TCP是面向鏈接的,但這並非必須的。

HTTP/1.0曾經爲每個請求/迴應交換都打開一個TCP鏈接,致使了2個缺點:打開一個鏈接須要屢次的消息往返所以很慢。可是當多個消息週期性發送時,這就變得更加高效:暖鏈接比冷鏈接更高效。

爲了減輕這些負擔,HTTP/1.1引入了流水線的概念和持久鏈接的概念:下層的TCP鏈接能夠經過Connection頭部來被部分控制。經過一個鏈接多個消息的方式來讓這個鏈接始終保持爲暖鏈接。

爲了更好的適合HTTP,設計一種更好的傳輸層協議就一直在進行中,Google就研發了一張以UDP爲基礎,能提供更可靠更有效傳輸層協議的QUIC。

HTTP能控制什麼

  • 緩存

文檔怎麼緩存可以經過HTTP來控制。服務器端告訴代理和客戶端什麼須要被緩存,緩存多久,而客戶端可以命令中間緩存代理來忽略存儲的文檔。

  • 開放同源限制
    HTTP能夠經過修改頭部來開放瀏覽器強制對Web網址作的分割限制。

  • 認證
    基本的認證功能(Basic Authenticate)能夠直接經過HTTP提供,使用Authenticate類似的頭部就能夠,或者用HTTP cookie來設定指定的會話。

  • 代理
    服務器和客戶端一般都處於內部網上,HTTP請求就要經過代理穿過網絡障礙,但不是全部的代理都是HTTP代理的。

  • 會話
    Cookies用一個服務端的狀態鏈接起每個請求。這就建立了會話,雖然基本的HTTP協議是無狀態協議。這頗有用,不只是由於能用的購物車這樣的電商業務上,更是由於,是的任何網站都可以配置頁面展示的東西。

HTTP流

當客戶端想要和服務端進行信息交互時(服務端是指做爲最終的服務器,或者是做爲中間代理),過程表現爲下面幾步:

  1. 打開一個TCP鏈接(或者重用以前的一個):TCP鏈接用來發送一條或多條請求,固然也用來接受迴應消息。客戶端可能重用一個已經存在的鏈接,或者也可能重開幾個新的與服務端的TCP鏈接。

  2. 發送一個HTTP報文:HTTP報文(在HTTP/2以前)是語義可能的。 在HTTP/2中,這些簡單的消息被封裝在了幀中。這使得報文不可能被直接讀出來,可是規則仍舊是相同的。

GET / HTTP/1.1
Host: developer.mozilla.org
Accept-Language: fr
  1. 讀取服務端返回的報文:
HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT
ETag: "51142bc1-7449-479b075b2891b"
Accept-Ranges: bytes
Content-Length: 29769
Content-Type: text/html

<!DOCTYPE html... (here comes the 29769 bytes of the requested web page)
  1. 關閉鏈接或者爲之後的請求重用鏈接。

HTTP報文

HTTP/1.1和更早的HTTP報文都是語義可讀的。在HTTP/2中,這些報文被嵌入到了一個新的二進制結構中 - 幀。幀能夠容許實現頗有優化,如複用和報文頭部的壓縮。即便只有原始HTTP報文的一部分以這種HTTP/2版本的方式發送出來,每一個報文的語義依舊不變,客戶端會重組原始的HTTP/1.1請求。所以用HTTP/1.1格式來考慮HTTP/2報文依舊有效。

有兩種HTTP報文的類型,請求與響應,每種都有其特定的格式。

請求

HTTP請求的一個例子:

GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1

請求由廈門的元素組成:

  • 一個HTTP的method,常常是由一個動詞像GET, POST或者一個名詞像OPTIONS,HEAD來定義客戶端的動做行爲的。一般客戶端的操做都是獲取資源(用GET方法)或者發送一個HTML form表單的值(用POST方法),雖然在一些狀況下也會有其餘的操做。
  • 要獲取的資源的路徑,一般是上下文中就很明顯的元素的URL,它沒有protocol(http://),domain(developer.mozilla.org),或是TCP的port(HTTP是80端口)
  • HTTP協議的版本號
  • 爲服務端表達其餘信息的可選擇性的headers
  • 對於一些像POST這樣的方法,報文的body就包含了發送的資源,這個body與迴應報文的body相似

響應

HTTP響應的一個例子:

HTTP/1.1 200 OK
Bdpagetype: 2
Bdqid: 0xa10573290003626a
Cache-Control: private
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Wed, 18 Apr 2018 08:23:03 GMT
Expires: Wed, 18 Apr 2018 08:23:03 GMT
Server: BWS/1.1

響應報文包含下面的元素:

  • HTTP的版本號
  • 一個狀態碼(status code),來告知對應的請求發送成功或失敗,以及失敗的緣由
  • 一個狀態信息,這個信息是非權威的狀態碼描述信息,也就是說能夠由服務器諮詢設定的
  • HTTP headers,與請求的很像
  • 可選的,可是比在請求報文中更加常見地包含獲取資源的body

總結

HTTP是很簡單可擴展的一直協議。結合了輕鬆添加頭部信息能力的Client-server結構使得HTTP能夠和Web的功能擴充一同發展。

即便HTTP/2爲了提升性能把HTTP報文嵌到HTTP報文幀中這一舉措增長了複雜度,可是從Web應用的角度看,報文的基本結束是沒有變化的,從HTTP/1.0發佈起就是相同的。會話流依舊很簡單,用一個簡單的HTTP message monitor就能夠查看它和debug。


(三)實戰Chrome開發者工具

步驟

  • 打開chrome瀏覽器,輸入網址:itest.info
  • 按F12打開chrome開發者工具,並選擇Network標籤
  • 刷新頁面
  • 找到itest.info請求

lbijA.md.png

結果(查看headers標籤)

1. General

Request URL: http://www.itest.info/
Request Method: GET
Status Code: 200 OK
Remote Address: 119.29.203.242:80
Referrer Policy: no-referrer-when-downgrade

2. Response Headers

Cache-Control: max-age=0, private, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Thu, 19 Apr 2018 01:19:54 GMT
ETag: W/"f64211eeefa54e7f13f091bb162d68f4"
Server: nginx/1.10.3 (Ubuntu)
Set-Cookie: _itest5_session=T0NTeUQ0OGFxaTl5aWR5MG4zTDlzUjJ3U3pNUWNvK096YkROcnVhL2w5clMrdGk5UGNUaTliaFNuM1F1R2hxWTBCOUpTd1BLRXNSNjkvbXQ5YUppZVJaZWxiZ3dMcnJVQTN0UWJqUFlFNTV1Zng3UnJ0ZnJYV0Z1NjBWSW9DV1gvNXA0a3hHR3J5YmV3U3FTdyt0WkdBPT0tLVFxQ2pxNzIvaXRRNU5wWWMrdHdLS2c9PQ%3D%3D--1967ac769cb1b7ee4f1e8203481f591f8bffea25; path=/; HttpOnly
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Request-Id: ccd6569c-3004-4ff3-bce2-88b3581d8941
X-Runtime: 0.008415
X-XSS-Protection: 1; mode=block

3. Request Headers

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: max-age=0
Connection: keep-alive
Cookie: _itest5_session=Zzc1WEkzSENiSHp1bSs0blZnMkNlS0l3VndVUXJEbTdiNGlXcmJuRjBsVVNDT080Rkg1V1Y4NFhqUmNVSU5vb2JVZC9VZU5CYnV1K3hBQlMrK21LUFBjdFJiVEo5SnNQQXo5Z0h0YzFIUWNndDI1L2ZhTkRrR0Zvc3REQnRZdTlkSUc1RXRmQjJMSFAxcGlVS1NNZDBnPT0tLS84akN1Mjl2U1dNQWkxRmJPaENjQmc9PQ%3D%3D--add7f6226ae3747a638a65c45a8fd7eecfc0fbce; Hm_lvt_906c6961a45234ebc29e93442b414707=1524100786; Hm_lpvt_906c6961a45234ebc29e93442b414707=1524100786
Host: www.itest.info
If-None-Match: W/"36e8ed1080e1b05a1f5df880fc857d08"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
X-FirePHP-Version: 0.0.6

(四)實戰yslow前端性能測試

安裝Yslow工具

  • 下載yslow插件(感謝pf04同窗提供yslow插件)
  • 打開chrome://extensions/,直接將插件拖拽過去便可

lpbPz.md.png

對ur.tencent.com前端頁面進行測試

  • chrome打開網頁ur.tencent.com

  • 點擊yslow的擴展程序圖標

lpuHh.md.png

  • 點擊Run Test

lplS6.md.png

  • 查看測試結果

lsWJR.md.png


(五)HTTP緩存

重用已經獲取的資源可以有效的提高網站與應用的性能。Web緩存可以減小延遲與網絡阻塞,進而減小顯示某個資源所用的時間。藉助HTTP緩存,Web站點變得更具備響應性。

總而言之合理使用緩存能夠加快站點的響應速度,讓用戶有頁面秒開的快感。

各類各樣的緩存

思考一個問題:從硬盤拷貝文件到指定文件夾比較快仍是網絡上傳下載一樣一份文件比較快?——拷貝比較快。

緩存就是儘可能讓咱們從本地讀取內容(這些內容每每是遠程服務器上相應內容的拷貝),從而替代從服務器上讀取內容的技術。

緩存是指存儲指定資源的一份拷貝,並在下次請求該資源時提供該拷貝的技術。當Web緩存發現請求的資源已經被存儲,它會攔截請求,返回該資源的拷貝,而不是去源服務器從新下載。這樣帶來的好處:緩解服務器端壓力,提示性能(獲取資源的耗時更短)。對於網站來講,緩存是達到高性能的重要組成部分。緩存須要合理配置,由於並非全部資源都是永久不變的;重要的是對一個資源的緩存應截止到其下一次發生改變(即不能緩存過時資源)。

1. 私有服務器緩存

私有緩存只能用於單獨用戶。可能已經見過瀏覽器設置中的「緩存」選項。瀏覽器緩存擁有用戶經過HTTP下載的全部文檔。這些緩存爲瀏覽過的文檔提供向後/向前導航,保存網頁,查看源碼等功能,能夠避免再次向服務器發起多餘的請求。它一樣能夠提供緩存內容的離線瀏覽。

2. 共享代理緩存

共享緩存能夠被多個用戶使用。例如,ISP或你所在的公司可能會架設一個web代理來做爲本地網絡基礎的一部分提供給用戶。這樣熱門的資源就會被重複使用,減小網絡擁堵與延遲。

緩存操做的目標

雖然HTTP緩存不是必須的,但重用緩存的資源一般是必要的。然而常見的HTTP緩存只能存儲GET響應,對於其餘類型的響應則無能爲力。緩存的關鍵主要包括request method和目標URI(通常只有GET請求才會被緩存)。廣泛的緩存案例:

  • 一個檢索請求的成功響應:狀態碼爲200,一個包含例如HTML文檔、圖片或者文件的響應
  • 不變的重定向:響應狀態碼爲301
  • 錯誤響應:響應狀態碼爲206,只返回局部的信息
  • 除了GET請求外,若是匹配到昨晚一個已被定義的cache鍵名的響應

針對一些特定的請求,也能夠經過關鍵字區分多個存儲的不一樣響應以組成緩存的內容。

緩存控制

Cache-control Headers

HTTP/1.1定義的Cache-Control頭用來區分對緩存機制的支持狀況,請求頭和響應頭都支持這個屬性。經過它提供不一樣的值來定義緩存策略。

徹底不支持緩存

緩存中不得存儲任何關於客戶端請求和服務端響應的內容。每次由客戶端發起的請求都會下載完整的響應內容。

不緩存內容

在釋放緩存內容前向服務端源地址發送請求以驗證緩存釋放有效。

私有緩存和公共緩存

  • public: 響應能夠被任何請求來源緩存。針對須要進行http身份驗證的頁面或者一些不能被順利緩存的響應碼,經過定義public以支持緩存。

  • private:響應的內容只能被惟一的用戶緩存,不能夠被共享緩存存儲。隱私模式下的瀏覽器會經過這種方式存儲緩存。

緩存過時

判斷緩存釋放過時的一個最經常使用的標誌爲max-age。相對Expires而言,max-age是距離請求發起的時間的秒數。針對應用中那些不會改變的文件,一般能夠收到設置必定時長以保證緩存有效,例如圖片、css、js等靜態資源。

緩存驗證

must-revalidate:在使用一些老的資源錢強制驗證狀態判斷是否過時。

Pragma Headers

Pragma是HTTP/1.0標準中定義的一個header屬性,請求中包含Pragma的效果跟在頭信息中定義Cache-Control:no-cache相同,可是HTTP的響應頭不支持這個屬性,因此它不能拿來徹底替代HTTP/1.1中定義的Cache-control頭。一般定義Pragma以向後兼容基於HTTP/1.0客戶端。

緩存有效性

一旦一個資源文件被存入緩存,理論上來講這個文件就永遠處於緩存中。可是緩存的存儲空間一般有限,這也意味着按期會移除一部分緩存文件。這個過程被稱爲緩存拋棄。另外一方面,針對那些在服務端發生改變的資源,應該作響應的緩存內容更新。由於HTTP協議在C-S架構中是無狀態的,服務端在資源發生變化時沒法通知到客戶端,經過定義過時時間以同步兩端的緩存資源。在過時時間前,資源緩存是有效的,反正則緩存失效。經過不停拋棄過時的緩存資源以保證資源的實時性。注意,舊的緩存不會被拋棄或者忽略;當發起一個針對舊緩存資源的請求時,會在請求頭裏帶上If-None-Match用來判斷緩存是否有效。若是有效,服務端返回304(Not Modified)和空的body以節省一部分帶寬。

對於含有特定頭信息的請求,會去計算緩存壽命。好比Cache-control:max-age=N的請求頭,相應的緩存的壽命就是N。一般狀況下,對於不含這個屬性的請求則會查看是否包含Expires屬性,經過比較Expires的值和頭裏面Date屬性的值來判斷是否緩存還有效。若是max-age和expires屬性都沒有,找找頭裏面的Last-Modified信息。若是有,緩存的壽命就等於頭裏面Data的值減去Last-Modified的值除以10。

緩存時長計算公式以下:

緩存時長 = 響應時間 + 緩存壽命 - 當前時間

響應時間指瀏覽器接收到服務端的響應的時間。

加速資源

更多地利用緩存資源,能夠提升網站的性能和相應速度。爲了優化緩存,過時時間設置得儘可能長是一種很好的測量。對應按期或者頻繁更新的資源,這麼作是比較穩妥的,可是對於那些長期不更新的資源會有點兒問題。這些固定的資源在必定時間內受益於這種長期保持的緩存策略,但一旦要更新就會很困難。特指網頁上引入的一些js/css文件,當它們變更時須要儘快更新線上資源。

web開發者發明了一種Steve Sounders稱做加速的技術。不頻繁更新的文件會使用特定的命名方式:在URL後面(一般是文件名後面)會加上版本號。加上版本號後的資源就被視做一個徹底新的獨立的資源,同時擁有一年甚至更長的緩存過時時長。可是這麼作也存在一個弊端,全部引用這個資源的地方都須要更新連接。web開發者們一般會纔有自動化構建工具在實際工做中完成這些瑣碎的工做。當低頻更新的資源(js/css)變更了,只用在高頻變更的資源文件(html)裏作入口的改動。

這種方法還有一個好處:同時更新兩個緩存資源不會形成部分緩存先更新而引發新舊文件內容不一致。對於互相有依賴關係的css和js文件,避免這種不一致性是很是重要的。

加在加速文件後面的版本號不必定是一個正式的版本號字符串,如1.1.3這樣或者其餘固定自增的版本數。它能夠是任何防止緩存碰撞的標記例如hash或者時間戳。

緩存驗證

用戶點擊刷新按鈕時會開始緩存驗證。若是緩存的響應頭信息裏含有「Cache-control:must-revalidate」的定義,在瀏覽的過程當中也會觸發緩存驗證。另外,在瀏覽器偏好設置裏設置Advanced-> Cache爲強制驗證緩存也能達到相同的效果。

當緩存的文檔過時後,須要進行緩存驗證或者從新獲取資源。只有在服務器返回強校驗器或者弱校驗器時纔會進行驗證。

ETag

做爲緩存的一種強校驗器,ETag響應頭是一個對用戶代理(User Agent,下面簡稱UA)不可知的值。對於像瀏覽器這樣的HTTP UA,不知道ETag表明什麼,值是多少。若是資源請求的響應頭裏含有ETag,客戶端能夠在後續的全部請求的頭中帶上If-None-Match頭來驗證緩存。

Last-Modified響應頭能夠做爲一種弱校驗器。說它弱是由於它是一次性的。若是響應頭裏含有這個信息,客戶端能夠在後續的一次請求中帶上If-Modified-Since來驗證緩存。

當向服務端發起緩存校驗的請求時,服務端會返回200 ok表示返回正常的結果或者304 Not Modified(不返回body)表示瀏覽器可使用本地緩存文件。304的響應頭也能夠同時更新緩存文檔的過時時間。

1. 帶Vary頭的響應

Vary HTTP響應頭決定了對於後續的請求頭,如何判斷是請求一個新的資源仍是使用緩存的文件。

當緩存服務器收到一個請求,只有當前的請求和原始(緩存)的請求頭跟緩存的響應頭裏的Vary都匹配,才能使用緩存的響應。

使用vary頭有利於內容服務的動態多樣性。例如,使用Vary:User-Agent頭,緩存服務器須要經過UA判斷是否使用緩存的頁面。若是須要區分移動端和桌面端的展現內容,利用這種方式就能避免在不一樣的終端展現錯誤的佈局。另外,它能夠幫助google或者其餘搜索引擎更好地發現頁面的移動版本,而且告訴搜索引擎沒有引入Cloaking。

由於移動版和桌面的客戶端的請求頭中的User-Agent不一樣,緩存服務器不會錯誤地把移動端的內容輸出到桌面端用戶。

2. max-age

max-age=120s,表示在120s以內,這個請求的內容都是能夠從緩存裏讀取的。

3. ETags

上面的請求120s以後就會過時,這時候若是瀏覽器再去發送一個請求去獲取資源的話,那仍是會蠻浪費的。畢竟資源的內容已經被瀏覽器緩存下來了。

經過ETags能夠解決這個問題。

服務器生成1個ETags,客戶端不須要知道這個ETags是如何生成的,在下一個請求發送時,客戶端向服務器帶上這個ETags,若是沒有變化,那麼證實內容沒變,本次下載能夠被忽略。


(六)HTTP請求

HTTP消息是服務器和客戶端之間交換數據的方式。有兩種類型的消息:

  • 請求 - 由客戶端發送用來觸發一個服務器上的動做;
  • 響應 - 來着服務器的應答

HTTP請求

** 起始行 **

HTTP請求是由客戶端發出的消息,用來使服務器執行動做。起始行(start-line)包含三個元素:

    1. 一個HTTP方法,一個動詞(像GET,PUT或者POST)或者一個名詞(像HEAD或者OPTIONS),描述要執行的動做。例如,GET表示要獲取資源,POST表示向服務器推送數據(建立或修改資源,或者產生要返回的臨時文件)。
    1. 請求目標(request target),一般是一個URL,或者是協議、端口和域名的絕對路徑,一般以請求的環境爲特徵。請求的格式因不一樣的HTTP方法而異。它能夠是:

a. 一個絕對路徑,末位跟上一個"?"和查詢字符串。這是最多見的形式,稱爲原始形式(origin form),被GET,POST, HEAD和OPTIONS方法所使用。

b. 一個完整的URL,被稱爲絕對形式(absolute form),主要在GET鏈接到代理時使用。

GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1

c. 由鬱悶和可選端口(以「:」爲前綴)組成的URL的authority component,稱爲authority form。僅在使用CONNECT創建HTTP隧道時才使用。

CONNECT developer.mozilla.org:80 HTTP/1.1

d. 星號形式(asterisk form),一個簡單的星號(/*/),配合OPTIONS方法使用,表明整個服務器。

    1. HTTP版本(HTTP version),定義了剩餘報文的結構,做爲對指望的響應版本的指示符。

** Headers **

來自請求的HTTP headers遵循和HTTP header相同的基本結構:不區分大小寫的字符串,緊跟着的冒號(:)和一個結構取決於header的值。這個header(包括值)由一行組成,這一行能夠至關長。

有須要請求頭可用,它們能夠分爲幾組:

  • General headers, 例如 Via,適用於整個報文。
  • Request headers, 例如User-Agent, Accept-Type,經過進一步的定義(例如Accept-Language), 或者給定上下文(例如Referer),或者進行有條件的限制(例如If-None)來修改請求。
  • Entity headers,例如Content-Length,適用於請求的body。顯然,若是請求中沒有任何body,則不會發送這樣的頭文件。

** Body **

請求的最後一部分是它的body。不是全部的請求都有一個body:例如獲取資源的請求,GET,HEAD, DELETE和OPTIONS,一般他們不須要body。有些請求將數據發送到服務器以便更新數據:常見的狀況是POST請求(包含HTML表單數據)。

Body大體可分爲兩類:

  • Singel-resource bodies,由一個單文件組成。該類型body由兩個header定義:Content-TypeContent-Length

  • Multiple-resource bodies, 由多部分body組成,每一部分包含不一樣的信息位。一般是和HTML Forms連繫在一塊兒

HTTP響應

** 狀態行 **

HTTP響應的起始行被稱做狀態行(status line),包含如下信息:

    1. 協議版本,一般爲HTTP/1.1
    1. 狀態碼(status code),代表請求是成功或失敗。常見的狀態碼是200,400或302。
    1. 狀態文本(status text)。一個簡短的,純粹的信息,同狀態碼的文本描述,幫助人們理解該HTTP消息

一個典型的狀態行看起來像這樣的: HTTP/1.1 404 Not Found

** Headers **

響應的HTTP headers遵循和任何其餘header相同的結構:不區分大小寫的字符串,緊跟着冒號(:)和一個結構取決於header類型的值。整個header(包括其值)表現爲單行形式。

有不少響應頭可用,這些響應頭能夠分爲幾組:

  • General headers,例如Via,適用於整個報文;

  • Response header,例如VaryAccept-Ranges,提供其它不符合狀態行的關於服務器的信息;

  • Entity headers,例如Content-Length,適用於請求的body。顯然,若是請求中沒有任何body,則不會發送這樣的頭文件。

** Body **
響應的最好一部分是body。不是全部的響應都有body:具備狀態碼(如201或204)的響應,一般不會有body。

body大體可分爲三類:

  • Single-resource bodies, 由已知長度的單個文件組成。該類型的body由兩個header定義:Content-Type和Content-Length。

  • Single-resource bodies,由未知長度的單個文件組成,經過將Transfer-Encoding設置爲chunked 來使用chunks編碼。

  • Multiple-resource bodies,由多部分body組成,每部分包含不一樣的信息段。但這是比較少見的。


HTTP Cookie(也叫Web cookie或者瀏覽器Cookie)是服務器發送到用戶瀏覽器並保存在瀏覽器上的一塊數據,它會在瀏覽器下一次發起請求時被攜帶併發送到服務器上。比較經典的,能夠用來肯定兩次請求是否來自同一個瀏覽器,從而可以確認和保持用戶的登陸狀態。Cookie的使用是的基於無狀態的HTTP協議記錄穩定的狀態信息成爲了可能。

  • 會話狀態管理(如用戶登陸狀態、購物車)
  • 個性化設置(如用戶自定義設置)
  • 瀏覽器行爲跟蹤(如跟蹤分析用戶行爲)

Cookie可用於客戶端數據的存儲,在沒有其餘存儲辦法時,使用這種方式是可行的,但隨着如今瀏覽器開始支持各類各樣的存儲方式而逐漸被廢棄。因爲服務器指定Cookie之後瀏覽器的每次請求都會攜帶Cookie數據,這會帶來額外的性能負擔(尤爲是在移動環境下)。新的瀏覽器API已經容許開發者直接在本地存儲數據,如可使用Web storage API(本地存儲和會話存儲)和IndexedDB。

建立cookie

當服務器收到HTTP請求時,能夠在響應頭裏面增長一個Set-Cookie頭部。瀏覽器收到響應以後會取出Cookie信息並保存,以後對該服務器每一次請求中都經過Cookie請求頭部將Cookie信息發送給服務器。另外,Cookie的過時時間、域、路徑、有效期、站點均可以根據須要來指定。

Set-Cookie響應頭部和Cookie請求頭部

服務器使用Set-Cookie響應頭部向用戶代理(通常指瀏覽器)發送Cookie信息。一個簡單的Cookie可能像這樣: Set-Cookie: <cookie名稱> = <cookie值>

服務器告訴客戶端要保存Cookie信息(服務端程序能夠是PHP、Node.js、Python或者Ruby on Rails等語言所寫),響應的數據裏面應該包含Set-Cookie頭,瀏覽器收到以後會降Cookie保存。

對該服務器發起的每一次顯得呃請求,瀏覽器都會將以前保存的Cookie信息經過Cookie請求頭髮送給服務器。

會話期Cookie

會話期Cookie是最簡單的Cookie:瀏覽器關閉以後它會被自動刪除,也就是它僅在會話期間有效。會話期Cookie不須要指定過時時間(Expires)或者有效期(Max-Age)。須要注意的是,有效瀏覽器提供了會話恢復的功能,這種狀況下即便關閉了瀏覽器會話期Cookie也會被保存,就好像瀏覽器歷來沒有關閉同樣。

持久Cookie

和關閉瀏覽器便失效不一樣,持久Cookie能夠指定一個特定的過時時間(Expires)或者有效期(Max-Age)

Set-Cookie: id=a3fWa;Expires=Web, 21 Oct 2015 07:28:00 GMT;

安全和HttpOnly類型Cookie

只有在使用SLL和HTTPS協議向服務器發起請求時,才能確保Cookie被安全地發送到服務器。HttpOnly標誌並無給你提過額外的加密或者安全性上的能力,當整個機器暴露在不安全的環境時,切記毫不能經過HTTP Cookie存儲、傳輸機密或者敏感信息。

HTTP-only類型的Cookie不能使用Javascript經過Document.cookie屬性來訪問,從而可以在必定程度上阻止跨域腳本攻擊(XSS)。當你不須要在JavaScript代碼中訪問你的Cookie時,能夠將該Cookie設置成HttpOnly類型。特別地,當你的Cookie僅僅是用於定義會話的狀況下,最好給它設置一下HttpOnly標誌。

Cookie的做用域

Domain和Path指令定義了Cookie的做用域,即須要發送Cookie的URL集合。

Domain指令規定了須要發送Cookie的主機名。若是沒有指定,默認爲當前的文檔地址上的主機名(可是不包含子域名)。若是指定了Domain,則通常包含子域名。

若是設置了Domain=mozilla.org,則Cookie包含在子域名中(如developer.mozilla.org)。

Path指令代表須要發送Cookie的URL路徑。字符%x2F(即「/」)用做文件夾分隔符,子文件夾也會被匹配到。

同站Cookie

同站Cookie容許服務器指定在跨站請求時Cookie是否會被髮送,從而能夠阻止跨站請求僞造攻擊(CSRF)。


安全

當整個機器暴露在不安全的環境時,切記毫不能經過HTTP Cookie存儲、傳輸機密或者敏感信息。

會話挾持和XSS

在Web應用中,Cookie經常用例標記用戶和會話受權。所以,若是竊取了Web應用的Cookie,可能致使受權用戶的會話受到攻擊(能夠能會致使攻擊者得到用戶的身份)。經常使用的竊取Cookie的方法有利用社會工程學進行攻擊和利用應用程序的漏洞進行XSS攻擊。

HttpOnly類型的Cookie因爲阻止了JavaScript對Cookie進行訪問而能在必定程度上環境此類攻擊。

跨站請求僞造(CSRF)

維基百科有一個比較好的CSRF的例子:有一張並不真實存在的圖片(多是在不安全聊天室或論壇),其實是向你的銀行服務器發送了提現請求。

<img src="http://bank.example.com/withdraw?account=bob&amount=1000000&for=mallory">

當你打開含有這張圖片的HTML頁面是,若是你已經等了了你的銀行帳戶而且還有效(並且沒有其餘驗證步驟),你的銀行裏的錢可能會被自動轉走。這裏有一些方法能夠阻止該類事情的發生:

  • 對用戶輸入進行過濾來阻止XSS;
  • 任何敏感的操做都應該來確認;
  • 用於敏感信息的Cookie只能擁有較短的生命週期;

追蹤和隱私

1.第三方Cookie

每一個Cookie都有與之關聯的域(Domain),若是Cookie的域和頁面的域是同樣的,那麼稱爲這個Cookie爲第一方Cookie,若是Cookie的域和頁面的域不同,則稱之爲第三方Cookie。大多數瀏覽器默認狀況下都容許第三方Cookie,可是能夠經過附加組件來阻止第三方Cookie。

2.殭屍Cookie和刪不掉的Cookie

Cookie的一個極端使用例子是殭屍Cookie(也稱爲刪不掉的Cookie)。這類Cookie較難以刪除,甚至刪除以後會自動重現。

相關文章
相關標籤/搜索