持久鏈接ajax
什麼是持久鏈接?顧名思義,就是"持久"的鏈接。以前說到過,爲了完成一個HTTP事務,服務器和客戶端之間要創建一條TCP鏈接來傳輸報文,這個事務結束之後通常都會直接把它關閉,這是正常的模式。但是這樣會形成網絡使用效率的下降,爲何呢?有這麼幾點緣由:瀏覽器
每次創建鏈接的時候都要通過三次握手等必須的程序,若是咱們擁有一條能夠一直使用的鏈接的話,也就意味着咱們只須要進行一次鏈接的創建,這就省去了每次創建鏈接的時間。服務器
上一篇心得中提到過了,使用過的鏈接會比新創建的鏈接速度會快一些,這是因爲TCP鏈接慢啓動的特性,每次創建新的鏈接,固然不如已經被調教的很好的鏈接速度快咯。網絡
每一個鏈接對於服務器和客戶端來講都是負擔,能少開儘可能少開,固然是在不影響功能和體驗的前提下。post
如今不少方案都會採用持久鏈接+新鏈接結合的方式,這種方式儘量的減小了新建鏈接的浪費,同時當現有鏈接沒有辦法知足需求的時候,能夠創建新鏈接知足需求,比較靈活。現有的持久鏈接類型有兩種:HTTP/1.0+的keep-alive和HTTP/1.1的persistent.性能
keep-alive測試
先來看來keep-alive,先上圖:spa
這個是百度首頁的一個HTTP事務,能夠看到有個首部connection:keep-alive,這個就是第一種持久鏈接了。下面來看下這個持久鏈接是怎麼創建的:代理
這個就是請求的過程了:客戶端先發出請求,以connection:keep-alive的形式傳向服務器,若是服務器接受的請求的話響應中就會帶有connection:keep- alive.事務
當使用了connection:keep-alive時,可使用keep-alive首部傳遞一些關於持久鏈接的參數:timeout表示持續時間,max表示但願還在這條持久鏈接上傳輸多少個HTTP服務,可是這些都不是承諾值,也就是說隨時均可以反悔。
接下來講說keep-alive持久鏈接須要注意的一些地方:
若是要是用持久鏈接,那麼就必定要有正確的content-length這個描述主體長度的首部,由於持久鏈接會連續的傳輸HTTP事務,而判斷連續的HTTP事 務之間的分界點就是靠content-length告訴的主體的長度了,若是錯誤或沒有告訴主體的長度的話,那麼就沒辦法知道這個事務在哪裏結束了。
代理和網管必須再轉發以前刪除connection:keep-alive這個首部,這個涉及到啞代理問題,後面會說到。
由於持久鏈接能夠隨時關閉,因此必定要作好遇到當請求發出去響應還沒回送回來的時候持久鏈接就斷開的狀況的準備,也就是有些時候可能要重新發送請求。
啞代理和聰明的代理
這裏先說明下啞代理和聰明的代理的區別:啞代理只是單純的轉發請求,並不能進行解析處理、維持持久鏈接等其餘工做,而聰明的代理能夠解析接收到的報文同時能夠維持持久鏈接。
如上圖,當客戶端與服務器之間存在不解析直接轉發的代理時,connection:keep-alive這個首部是直接轉發給服務器的,服務器接收了這個請求以後,就會向客戶端發送帶有connection:keep-alive的響應,一樣盲代理不會解析響應,直接將所有響應轉發回客戶端。由於客戶端收到了這個首部,就認爲創建持久鏈接已經成功了,可是中間的」笨代理「,並不知道這些事情,笨代理只有一種行爲模式:在轉發請求和回送服務器響應請求以後就認爲此次事務結束了,等待鏈接斷開,而這時因爲connection:keep-alive首部已經發送到服務器和客戶端,雙方都認爲持久鏈接已經創建完成,這樣就變成了兩邊認爲持久鏈接OK而中間的啞代理等待鏈接斷開的狀況,這種狀況下若是客戶端再一次在這條鏈接上發送請求,請求就會在亞代理處中止,由於啞代理已經在等待鏈接關閉。這種狀態會致使瀏覽器一直處於掛起狀態,直到客戶端或服務器之中一個鏈接超時,關閉鏈接爲止,一段美好的牽手就這麼沒了(啞代理就是把內容原封不動的轉發到代理)。
爲了不這種狀況,現代的代理是不會轉發connection:keep-alive這個首部的。
爲了防止這個問題,網景提出了一個方案,採用插入Proxy-connection的方式,上圖:
來看看這個方案如何解決問題:
首先客戶端發送Proxy-connection首部請求,這是一個非標準請求,也就是說即便服務器接收到這個首部也不知道他是幹什麼的,在服務器眼中它只知道客戶端申請持久鏈接的首部爲connection:keep-alive
啞代理的模式:報文來到了代理的位置,啞代理的話會直接轉發請求不解析處理,則Proxy-connection這個首部直接被髮給服務器,因爲服務器不識別,因此直接忽略到這個首部,這樣服務器在返回響應的時候便不會帶有connection:keep-alive首部,當響應到達客戶端的時候,客戶端發現響應中沒有connection:keep-alive首部,就認爲服務器拒絕了持久鏈接的請求,也就是說客戶端判斷服務器是否接受持久鏈接請求還是靠響應是否存在connection首部來進行的。
聰明的代理的模式:聰明的代理會對請求進行解析,發現有 Proxy-connection這個首部的時候,便會把這個首部替換成connection:keep-alive,因爲服務器只能識別connection首部,當它發現有這個首部的時候,就知道客戶端進行了持久鏈接請求,就在響應中添加connection首部,回送給客戶端。當客戶端收到帶有connection首部的響應時,便認爲持久鏈接創建成功,而正好中間的聰明的路由也能夠維持持久鏈接,這樣整條鏈接就處於客戶端OK代理OK服務器OK的狀態,能夠繼續使用該持久鏈接進行報文發送。
從上面所說的,我以爲這個方案其實就是至關於對中間代理的類型進行了一次判斷。
可是這個方案只能解決中間只有一個代理的狀況,若是聰明的任意一邊還存在一個啞代理,那麼仍會出現最開始的啞代理問題。
persistent
HTTP/1.1的持久鏈接默認是開啓的,只有首部中包含connection:close,纔會事務結束以後關閉鏈接。固然服務器和客戶端仍能夠隨時關閉持久鏈接。
當發送了connection:close首部以後客戶端就沒有辦法在那條鏈接上發送更多的請求了。固然根據持久鏈接的特性,必定要傳輸正確的content-length。
還有根據HTTP/1.1的特性,是不該該和HTTP/1.0客戶端創建持久鏈接的。最後,必定要作好重發的準備。
管道化鏈接
HTTP/1.1容許在持久鏈接上使用管道,這樣就不用等待前一個請求的響應,直接在管道上發送第二個請求,在高延遲下,提升性能。
管道化鏈接的限制:
不是持久鏈接就不能使用管道。
必須按照一樣的發送順序回送響應,由於報文沒有標籤,極可能就順序就亂咯。
由於能夠隨時關閉持久鏈接,因此要隨時作好重發準備
不該該使用管道化發送重複發送會有反作用的請求(如post,重複提交)。
就到這裏了,畫着好累。。。