HTTP首部Connection實踐

引子

在HTTP/1.0 時代,HTTP與TCP默認傳輸?shù)年P(guān)系如圖1所示,每次HTTP請求和響應(yīng)都發(fā)生一次TCP三次握手和四次揮手。以HTTP/1.0 時代的網(wǎng)絡(luò)通信量來看,都是些容量很小的文本傳輸,所以圖1的傳輸方式性能沒有較大問題。


圖1 HTTP/1.0默認傳輸過程

可是隨著互聯(lián)網(wǎng)普及,Web網(wǎng)頁的圖片逐漸多起來。比如,使用瀏覽器瀏覽一個包含多張圖片的HTML頁面時,在發(fā)送HTTP請求訪問HTML頁面資源的同時,也會請求該HTML頁面里包含的其他資源,比如圖片等靜態(tài)文件。因此,每次的請求都會造成無謂的TCP連接建立和斷開,增加網(wǎng)絡(luò)通信量的開銷,如圖2所示。


圖2 一個Web頁面的多次HTTP請求

為了解決上述問題,HTTP/1.1和一部分的HTTP/1.0想出了持久連接的辦法,即只要任意一端沒有明確提出斷開連接,則保持TCP連接狀態(tài),如圖3所示。
圖3 HTTP持久連接
HTTP持久連接不是絕對高性能

HTTP持久連接允許在事務(wù)處理結(jié)束之后將TCP連接保持在打開狀態(tài),以便為未來的HTTP請求重用現(xiàn)存的連接。在事務(wù)處理結(jié)束之后仍然保持在打開狀態(tài)的TCP連接被稱為持久連接。持久連接會在不同事務(wù)之間保持打開狀態(tài),直到客戶端或服務(wù)器決定將其關(guān)閉為止。
優(yōu)點:重用已對目標(biāo)服務(wù)器打開的空閑持久連接,可以避開緩慢的連接建立階段,更快速地進行數(shù)據(jù)的傳輸。
缺點:管理不當(dāng)可能會積累出大量的空閑連接,耗費本地客戶端以及遠程服務(wù)器上的資源。
非持久連接會在每個事務(wù)處理結(jié)束之后關(guān)閉。

HTTP持久連接實現(xiàn)手段是HTTP首部添加Connection字段
  • Connection: keep-alive , 開啟HTTP持久連接,HTTP 1.1默認值
  • Connection: close , 關(guān)閉HTTP持久連接,HTTP 1.0默認值
HTTP keep-alive與TCP keep-alive區(qū)別
  • HTTP keep-alive參數(shù)為了減少TCP連接和斷開而提出的一種解決方案,HTTP持久連接即TCP長連接。
  • TCP keep-alive參數(shù)主要為探測長連接的存活狀況,即TCP?;罟δ堋?/li>

本文將對HTTP首部Connction實踐,對比keep-alive/close兩個值在HTTP和TCP的表現(xiàn)情況。后端使用Spring boot+Java,前端使用HTML+CSS。

HTTP Request首部Connection

如果Client希望HTTP使用持久連接,在Request首部指定Connection: keep-alive,否則指定Connection: close。
后端Java代碼如下:

package com.demo.web.http;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("http")
public class ConnectionController {
    @RequestMapping("/connection")
    public String connection(@RequestHeader(value="Connection") String connection) {
        System.out.println("Connection: " + connection);
        return "http/connection";
    }
}

前端HTML代碼:

<!DOCTYPE HTML>
<html>
<head>
    <title>HTTP Connection Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>實踐HTTP Connection</h3>
<a href="connection">刷新頁面</a>
</body>
</html>

后端服務(wù)啟動端口8080,執(zhí)行nc 127.0.0.1 8080,輸入如下兩行命令,兩次回車,HTTP Request首部Connection: keep-alive,執(zhí)行情況如圖4第一個紅色方框,緊接著返回Web頁面,后端日志打印Connection: keep-alive。從圖5抓包紅色方框看,TCP沒有發(fā)起四次揮手釋放連接,HTTP請求保持TCP長連接。

GET http://127.0.0.1:8080/http/connection HTTP/1.1
Connection: keep-alive
圖4 HTTP持久連接請求

圖5 HTTP請求tcpdump

再次輸入如下兩行命令,兩次回車,HTTP Request首部Connection: keep-alive,執(zhí)行情況如圖4第二個紅色方框,緊接著返回Web頁面,后端日志打印Connection: keep-alive。從圖5綠色方框看,TCP沒有發(fā)起四次揮手釋放連接,HTTP請求保持TCP長連接。

GET http://127.0.0.1:8080/http/connection HTTP/1.1
Connection: keep-alive

再次輸入如下兩行命令,兩次回車,HTTP Request首部Connection: close,執(zhí)行情況如圖6綠色方框,緊接著返回Web頁面,后端日志打印Connection: close。從圖5藍色色方框看,TCP發(fā)起四次揮手釋放連接,HTTP請求的TCP連接斷開。

GET http://127.0.0.1:8080/http/connection HTTP/1.1
Connection: close
圖5 HTTP請求

HTTP Response首部Connection

如果Server希望HTTP使用長連接,在Response首部指定Connection: keep-alive,否則指定Connection: close。
后端Java代碼如下:

package com.demo.web.http;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;

@Controller
@RequestMapping("http")
public class ConnectionController {
    @RequestMapping("/connection")
    public String connection(HttpServletRequest request, HttpServletResponse response,
                             @RequestHeader(value="Connection") String connection) {
        System.out.println("Connection: " + connection);
        response.addHeader("Connection", "keep-alive");
        return "http/connection";
    }
}

前端HTML代碼:

<!DOCTYPE HTML>
<html>
<head>
    <title>HTTP Connection Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>實踐HTTP Connection</h3>
<a href="connection">刷新頁面</a>
</body>
</html>

HTTP/1.1的Request首部Connection默認為keep-alive,當(dāng)后端返回Response首部Connection: keep-alive,訪問http://127.0.0.1:8080/http/connection,如圖6所示,點擊按鈕刷新頁面。從圖7綠色方框和紅色方框看,TCP沒有發(fā)起四次揮手釋放連接,HTTP請求保持TCP長連接。超時后TCP連接會自動斷開,從四次揮手的開始時間21:31:40.000676與Web頁面請求結(jié)束時間21:30:39.945438看,TCP長連接60s超時。

圖6 HTTP頁面訪問

圖7 HTTP頁面訪問tcpdump

HTTP/1.0與HTTP/1.1 首部Connection默認值對比

后端Java代碼:

package com.demo.web.http;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("http")
public class ConnectionController {
    @RequestMapping("/connection")
    public String connection() {
        return "http/connection";
    }
}

后端服務(wù)啟動端口8080,執(zhí)行nc 127.0.0.1 8080,輸入如下命令,兩次回車,重復(fù)執(zhí)行如下命令,如圖8所示,TCP沒有發(fā)起四次揮手釋放連接,HTTP請求保持TCP長連接,所以HTTP/1.1 首部Connection默認值為keep-alive。

GET http://127.0.0.1:8080/http/connection HTTP/1.1
圖8 HTTP/1.1持久連接

后端服務(wù)啟動端口8080,執(zhí)行nc 127.0.0.1 8080,輸入如下命令,兩次回車,如圖9所示,TCP釋放連接,HTTP請求也結(jié)束,所以HTTP/1.0 首部Connection默認值為close。

GET http://127.0.0.1:8080/http/connection HTTP/1.0
圖9 HTTP 1.0

再進一步,后端服務(wù)啟動端口8080,執(zhí)行nc 127.0.0.1 8080,輸入如下命令,兩次回車,如圖9所示,TCP釋放連接,HTTP請求也結(jié)束,所以HTTP默認使用1.0版本。

GET http://127.0.0.1:8080/http/connection
圖10 HTTP默認版本

HTTP持久連接的數(shù)據(jù)傳輸完成識別

HTTP首部定義Connection: keep-alive后,客戶端、服務(wù)端怎么知道本次傳輸結(jié)束呢?兩部分:

  • 靜態(tài)頁面通過Content-Length提前告知對方數(shù)據(jù)傳輸大小,具體可以參考拙作HTTP Content-Length深入實踐
  • 動態(tài)頁面不能通過Content-Length提前告知對方數(shù)據(jù)傳輸大小,它是分塊傳輸(chunked),這時候就要根據(jù)chunked編碼來判斷,chunked編碼的數(shù)據(jù)在最后有一個空chunked塊,表明本次傳輸數(shù)據(jù)結(jié)束,HTTP頭部使用Transfer-Encoding: chunked來代替Content-Length。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 連接管理 重點 http是如何使用tcp連接的; tcp連接的時延、瓶頸以及存在的障礙 http的優(yōu)化包括并行連接...
    shenyifu閱讀 849評論 0 3
  • 本篇文章篇幅比較長,先來個思維導(dǎo)圖預(yù)覽一下。 一、概述 1.計算機網(wǎng)絡(luò)體系結(jié)構(gòu)分層 2.TCP/IP 通信傳輸流 ...
    滌生_Woo閱讀 56,193評論 24 557
  • 這里講的請求是后端DevOps可以控制的范圍內(nèi),不包括DNS解析,層層的路由等等,一切都從請求到達我們自己架設(shè)的服...
    MMoooooon閱讀 2,234評論 0 3
  • 當(dāng)我們在瀏覽器的地址欄輸入 www.linux178.com ,然后回車,回車這一瞬間到看到頁面到底發(fā)生了什么呢?...
    Ddaidai閱讀 1,284評論 0 12
  • 每個人都有 想要將開心喜悅或煩憂 與人訴說分享的需求 曾經(jīng)只有一個人的時候 就自己默默回味 直到遇見另一個人 以為...
    瑾瑜菇?jīng)?/span>閱讀 360評論 0 0

友情鏈接更多精彩內(nèi)容