時間:1991年發佈html
HTTP 是基於 TCP/IP 協議的應用層協議。瀏覽器
它不涉及數據包(packet)傳輸,主要規定了客戶端和服務器之間的通訊格式緩存
默認使用80端口服務器
該版本極其簡單,只有一個命令GETmarkdown
協議規定,服務器只能迴應HTML格式的字符串,不能迴應別的格式app
服務器將響應數據發送完畢,就關閉TCP鏈接dom
時間:1996年發佈性能
任何格式的內容均可以發送,包括文字,圖片,二進制,視頻等優化
除了GET命令,還引入了POST命令和HEAD網站
請求和響應的格式加入頭信息(HTTP header)
新增狀態碼(status code)、多字符集支持、多部分發送(multi-part type),權限(Authorization)、緩存(cache)、內容編碼(content encoding 即數據壓縮方式)等
(短鏈接)每一個請求創建一個TCP鏈接,每一個TCP鏈接只能發送一個請求,發送數據完畢,鏈接就關閉,若是還要請求其餘資源,就必須再新建一個鏈接
TCP鏈接的新建成本很高,由於須要客戶端和服務器三次握手,而且開始時發送速率較慢(slow start)。因此,HTTP 1.0版本的性能比較差。隨着網頁加載的外部資源愈來愈多,這個問題就愈發突出了。
爲了解決這個問題,有些瀏覽器在請求時,用了一個非標準的Connection字段(創建長鏈接)
Connection: keep-alive
複製代碼
這個字段要求服務器不要關閉TCP鏈接,以便其餘請求複用。服務器一樣迴應這個字段。
Connection: keep-alive
複製代碼
一個能夠複用的TCP鏈接就創建了,直到客戶端或服務器主動關閉鏈接。可是,這不是標準字段,不一樣實現的行爲可能不一致,所以不是根本的解決辦法。
時間:1997年1月
即TCP鏈接默認不關閉,能夠被多個請求複用,不用聲明Connection: keep-alive。
能夠主動關閉TCP鏈接,規範的作法是,客戶端在最後一個請求時,發送Connection: close,明確要求服務器關閉TCP鏈接。
Connection: close
複製代碼
即在同一個TCP鏈接裏面,客戶端能夠同時發送多個請求,這樣就進一步改進了HTTP協議的效率
舉例來講,客戶端須要請求兩個資源。之前的作法是,在同一個TCP鏈接裏面,先發送A請求,而後等待服務器作出迴應,收到後再發出B請求。管道機制則是容許瀏覽器同時發出A請求和B請求,可是服務器仍是按照順序,先回應A請求,完成後再回應B請求。
在同一個TCP鏈接中能夠同時傳送多個響應,該字段用以區分哪些內容屬於哪一個響應
Content-Length: 3495
複製代碼
上面代碼告訴瀏覽器,本次迴應的長度是3495個字節,後面的字節就屬於下一個迴應了。 在1.0版中,Content-Length字段不是必需的,由於瀏覽器發現服務器關閉了TCP鏈接,就代表收到的數據包已經全了。
使用Content-Length字段的前提條件是,服務器發送迴應以前,必須知道迴應的數據長度。
對於一些很耗時的動態操做來講,這意味着,服務器要等到全部操做完成,才能發送數據,顯然這樣的效率不高。更好的處理方法是,產生一塊數據,就發送一塊,採用」流模式」(stream)取代」緩存模式」(buffer)。
所以,1.1版規定能夠不使用Content-Length字段,而使用」分塊傳輸編碼」(chunked transfer encoding)。只要請求或迴應的頭信息有Transfer-Encoding字段,就代表迴應將由數量未定的數據塊組成。
每一個非空的數據塊以前,會有一個16進制的數值,表示這個塊的長度。最後是一個大小爲0的塊,就表示本次迴應的數據發送完了。下面是一個例子
有了Host字段,就能夠將請求發往同一臺服務器上的不一樣網站,爲虛擬主機(在一臺物理服務器上能夠存在多個虛擬主機,而且它們共享一個IP地址)的興起打下了基礎
HOST字段:指明瞭請求將要發送到的服務器主機名和端口號
HTTP/1.1在1.0的基礎上加入了一些cache的新特性,引入了實體標籤,通常被稱爲e-tags,新增更爲強大的Cache-Control頭
ETags
驗證緩存的responseETag
來傳遞驗證令牌;瀏覽器發起上一次的get請求已經超過了120s(Cache-Control:max-age=120)
,而且瀏覽器發起對同一資源的新請求。
首先,瀏覽器檢查本地緩存並找到先前的響應。可是響應已過時,沒法使用以前的response。
此時,瀏覽器能夠發起新的請求並獲取新的完整的響應結果,可是效率相對低下,由於資源並無被修改,沒有必要重複下載已經存在緩存中的資源。
這就是ETag
會解決的問題。服務器生成並返回任意ETag
,該ETag
一般是文件內容的散列或其餘指紋。客戶端不須要知道ETag
是如何生成的;它只須要在下一個請求時將其發送到服務器。若是ETag
的值仍然相同,則資源未更改,能夠跳過下載,訪問本地緩存資源。
雖然1.1版容許複用TCP鏈接,可是同一個TCP鏈接裏面,全部的數據通訊是按次序進行的。服務端是按隊列順序處理請求的,服務器只有處理完一個迴應,纔會進行下一個迴應。假如前面的請求處理時間很長,後面就會有許多請求排隊等着,這樣就形成了「隊頭阻塞」的問題;同時HTTP是無狀態的鏈接,所以每次請求都須要添加劇復的字段,下降了帶寬的利用率。
多路複用帶來一個新的問題是,在鏈接共享的基礎之上有可能會致使關鍵請求被阻塞。SPDY容許給每一個request設置優先級,這樣重要的請求就會優先獲得響應。好比瀏覽器加載首頁,首頁的html內容應該優先展現,以後纔是各類靜態資源文件,腳本文件等加載,這樣能夠保證用戶能第一時間看到網頁內容。
爲了不這個問題,只有兩種方法:一是減小請求數,二是同時多開持久鏈接。這致使了不少的網頁優化技巧,好比合並腳本和樣式表、將圖片嵌入CSS代碼、域名分片(domain sharding)等等。若是HTTP協議設計得更好一些,這些額外的工做是能夠避免的。
2015年,HTTP/2 發佈。它不叫 HTTP/2.0,是由於標準委員會不打算再發布子版本了,下一個新版本將是 HTTP/3。
HTTP/1.1 版的頭信息確定是文本(ASCII編碼),數據體能夠是文本,也能夠是二進制。HTTP/2 則是一個完全的二進制協議,頭信息和數據體都是二進制,而且統稱爲"幀"(frame):頭信息幀和數據幀。
二進制協議的一個好處是,能夠定義額外的幀。HTTP/2 定義了近十種幀,爲未來的高級應用打好了基礎。若是使用文本實現這種功能,解析數據將會變得很是麻煩,二進制解析則方便得多。
HTTP/2 複用TCP鏈接,在一個鏈接裏,客戶端和瀏覽器均可以同時發送多個請求或迴應,並且不用按照順序一一對應,這樣就避免了"隊頭堵塞"。
舉例來講,在一個TCP鏈接裏面,服務器同時收到了A請求和B請求,因而先回應A請求,結果發現處理過程很是耗時,因而就發送A請求已經處理好的部分, 接着迴應B請求,完成後,再發送A請求剩下的部分。
這樣雙向的、實時的通訊,就叫作多工(Multiplexing)。
由於 HTTP/2 的數據包是不按順序發送的,同一個鏈接裏面連續的數據包,可能屬於不一樣的迴應。所以,必需要對數據包作標記,指出它屬於哪一個迴應。
HTTP/2 將每一個請求或迴應的全部數據包,稱爲一個數據流(stream)。每一個數據流都有一個獨一無二的編號。數據包發送的時候,都必須標記數據流ID,用來區分它屬於哪一個數據流。另外還規定,客戶端發出的數據流,ID一概爲奇數,服務器發出的,ID爲偶數。
數據流發送到一半的時候,客戶端和服務器均可以發送信號(RST_STREAM
幀),取消這個數據流。1.1版取消數據流的惟一方法,就是關閉TCP鏈接。這就是說,HTTP/2 能夠取消某一次請求,同時保證TCP鏈接還打開着,能夠被其餘請求使用。
客戶端還能夠指定數據流的優先級。優先級越高,服務器就會越早迴應。
HTTP 協議不帶有狀態,每次請求都必須附上全部信息。因此,請求的不少字段都是重複的,好比Cookie
和User Agent
,如出一轍的內容,每次請求都必須附帶,這會浪費不少帶寬,也影響速度。
HTTP/2 對這一點作了優化,引入了頭信息壓縮機制(header compression)。一方面,頭信息使用gzip
或compress
壓縮後再發送;另外一方面,客戶端和服務器同時維護一張頭信息表,全部字段都會存入這個表,生成一個索引號,之後就不發送一樣字段了,只發送索引號,這樣就提升速度了。
HTTP/2 容許服務器未經請求,主動向客戶端發送資源,這叫作服務器推送(server push)。
常見場景是客戶端請求一個網頁,這個網頁裏面包含不少靜態資源。正常狀況下,客戶端必須收到網頁後,解析HTML源碼,發現有靜態資源,再發出靜態資源請求。其實,服務器能夠預期到客戶端請求網頁後,極可能會再請求靜態資源,因此就主動把這些靜態資源隨着網頁一塊兒發給客戶端了。