深度解密HTTP通信細(xì)節(jié)

上一篇文章中眶拉,我們學(xué)會(huì)了用wireshark和tcpdump來(lái)分析TCP的“三次握手千埃,四次揮手”,非常好用忆植。這哥倆就是傳說(shuō)中的錘子放可,拿著錘子,看什么都像釘子朝刊!在這篇文章中耀里,我對(duì)準(zhǔn)了HTTP這顆釘子砸下去,咳咳拾氓。

為了對(duì)網(wǎng)絡(luò)數(shù)據(jù)包的“流轉(zhuǎn)”有更加深刻的理解冯挎,我在docker(遠(yuǎn)程)上部署一個(gè)服務(wù),支持http方式調(diào)用咙鞍。從客戶端(本地)用http方式請(qǐng)求其中的一個(gè)接口织堂,并得到響應(yīng)數(shù)據(jù)。同時(shí)本地通過(guò)wireshark抓包奶陈,遠(yuǎn)程用tcpdump抓包,然后分析過(guò)程中的所有通信細(xì)節(jié)附较。悲劇是把美好的東西撕碎給人看吃粒,而我則是把復(fù)雜的東西撕碎了給人看。

文章稍長(zhǎng)拒课,請(qǐng)?jiān)诳幢疚臅r(shí)保持耐心徐勃。我先通過(guò)工具獲取HTTP通信的數(shù)據(jù)包,再來(lái)抽絲剝繭早像,深入二進(jìn)制的天地里僻肖,解密HTTP所有的通信細(xì)節(jié)。分析過(guò)程中卢鹦,由點(diǎn)到面臀脏,將相關(guān)知識(shí)串接起來(lái)。保證全篇讀完之后冀自,你對(duì)HTTP的理解會(huì)上升一個(gè)臺(tái)階揉稚!

為了更好的閱讀體驗(yàn),我手動(dòng)貼上本文的目錄:

blog dir

HTTP報(bào)文截獲

背景介紹

我手頭現(xiàn)在有一個(gè)地理幾何相關(guān)的服務(wù)熬粗,它提供一組接口對(duì)外使用搀玖。其中有一個(gè)接口是Fence2Area. 使用方傳入一個(gè)圍欄(由點(diǎn)的列表組成,點(diǎn)由<經(jīng)度驻呐,緯度>表示)灌诅、點(diǎn)的坐標(biāo)系類型(谷歌地圖用的是wgs84, 國(guó)內(nèi)騰訊芳来、高德用的是soso, 而百度用的是另一套自己的坐標(biāo)系),接口輸出的則是圍欄的面積猜拾。

我請(qǐng)求服務(wù)的“Fence2Area”接口即舌,輸入圍欄(fence)頂點(diǎn)(lng, lat)坐標(biāo)、坐標(biāo)系類型(coordtype)关带,輸出的則是多邊形的面積(area).

一次正常的請(qǐng)求示例url, 這個(gè)大家都不陌生(我用docker_ip代替真實(shí)的ip):

http://docker_ip:7080/data?cmd=Fence2Area&meta={"caller":"test","TraceId":"test"}&request={"fence":[{"lng":10.2,"lat":10.2}, {"lng":10.2,"lat":8.2}, {"lng":8.2,"lat":8.2}, {"lng":8.2,"lat":10.2}],"coordtype":2}

請(qǐng)求發(fā)出后侥涵,服務(wù)器進(jìn)行處理,之后宋雏,客戶端收到返回的數(shù)據(jù)如下:

{
    "data": {
        "area": 48764135597.842606
    },
    "errstr": ""
}

area字段表示面積芜飘,errstr表示出錯(cuò)信息,空說(shuō)明沒(méi)有出錯(cuò)磨总。

抓包

在真正發(fā)送請(qǐng)求之前嗦明,需要進(jìn)行抓包前的設(shè)置。在本地mac蚪燕,我用wireshark; 而在遠(yuǎn)程docker上娶牌,我用tcpdump工具。

mac本地

設(shè)置wireshark包過(guò)濾器馆纳,監(jiān)控本地主機(jī)和遠(yuǎn)程docker之間的通信诗良。

ip.addr eq docker_ip

點(diǎn)擊開(kāi)始捕獲。

遠(yuǎn)程docker

該服務(wù)通過(guò)7080端口對(duì)外提供鲁驶,使用如下命令捕獲網(wǎng)絡(luò)包:

tcpdump -w /tmp/testHttp.cap port 7080 -s0

請(qǐng)求 && 分析

準(zhǔn)備工作做完鉴裹,我選了一個(gè)神圣的時(shí)刻,在本地通過(guò)瀏覽器訪問(wèn)如下url:

http://docker_ip:7080/data?cmd=Fence2Area&meta={"caller":"test","TraceId":"test"}&request={"fence":[{"lng":10.2,"lat":10.2}, {"lng":10.2,"lat":8.2}, {"lng":8.2,"lat":8.2}, {"lng":8.2,"lat":10.2}],"coordtype":2}

這樣本地的wireshark和遠(yuǎn)程的tcpdump都能抓取到HTTP網(wǎng)絡(luò)數(shù)據(jù)包钥弯。

關(guān)閉服務(wù)進(jìn)程

正式請(qǐng)求之前径荔,我們先看一下幾種特殊的情形。

首先脆霎,關(guān)閉gcs服務(wù)進(jìn)程总处,請(qǐng)求直接返回RST報(bào)文。

rst

如上圖睛蛛,我在請(qǐng)求的時(shí)候鹦马,訪問(wèn)服務(wù)端的另一個(gè)端口5010, 這個(gè)端口沒(méi)有服務(wù)監(jiān)聽(tīng),和關(guān)閉gcs服務(wù)進(jìn)程是同樣的效果忆肾〔ず欤可以看到卫旱,客戶端發(fā)送SYN報(bào)文棒假,但直接被遠(yuǎn)程docker RST掉了姜胖。因?yàn)榉?wù)端操作系統(tǒng)找不到監(jiān)聽(tīng)此端口的進(jìn)程蹬跃。

關(guān)閉docker

關(guān)閉docker, 由于發(fā)送的SYN報(bào)文段得不到響應(yīng)内舟,因此會(huì)進(jìn)行重試钧惧,mac下重試的次數(shù)為10次需五。

mac retry

先每隔1秒重試了5次讼撒,再用“指數(shù)退避”的時(shí)間間隔重試,2s, 4s, 8s, 16s, 32s. 最后結(jié)束摹闽。

重啟docker

先進(jìn)行一次正常的訪問(wèn)蹄咖,隨后重啟docker。并再次在本地訪問(wèn)以上url, 瀏覽器這時(shí)還是用的上一次的端口付鹿,訪問(wèn)到服務(wù)端后澜汤,因?yàn)樗呀?jīng)重啟了,所以服務(wù)端已經(jīng)沒(méi)有這個(gè)連接的消息了舵匾。因此會(huì)返回一個(gè)RST報(bào)文俊抵。

正常請(qǐng)求

服務(wù)正常啟動(dòng),正常發(fā)送請(qǐng)求坐梯,這次請(qǐng)求成功徽诲,那是當(dāng)然的,嘿嘿吵血!

normal_req_wireshark

這是在mac上用wireshark捕獲的數(shù)據(jù)包谎替,共7個(gè)包,前三個(gè)包為3次握手的包蹋辅,第四個(gè)包為HTTP層發(fā)送的請(qǐng)求數(shù)據(jù)钱贯,第五個(gè)包為服務(wù)端的TCP 確認(rèn)報(bào)文,第六個(gè)包為服務(wù)端在HTTP層發(fā)送的響應(yīng)數(shù)據(jù)侦另,第七個(gè)包為mac對(duì)第六個(gè)包的確認(rèn)報(bào)文秩命。

重點(diǎn)來(lái)關(guān)注后面幾個(gè)包,先看第四個(gè)包淋肾,

0x0000:  4500 0295 0000 4000 3606 623b ac17 ccdc
0x0010:  0a60 5cd4 db9b 1ba8 a59a 46ce 6d03 e87d
0x0020:  8018 1015 0ee7 0000 0101 080a 2e4c b2ef
0x0030:  0f20 3acf 4745 5420 2f64 6174 613f 636d
0x0040:  643d 4665 6e63 6532 4172 6561 266d 6574
0x0050:  613d 7b25 3232 6361 6c6c 6572 2532 323a
0x0060:  2532 3274 6573 7425 3232 2c25 3232 5472
0x0070:  6163 6549 6425 3232 3a25 3232 7465 7374
0x0080:  2532 327d 2672 6571 7565 7374 3d7b 2532
0x0090:  3266 656e 6365 2532 323a 5b7b 2532 326c
0x00a0:  6e67 2532 323a 3130 2e32 2c25 3232 6c61
0x00b0:  7425 3232 3a31 302e 327d 2c25 3230 7b25
0x00c0:  3232 6c6e 6725 3232 3a31 302e 322c 2532
0x00d0:  326c 6174 2532 323a 382e 327d 2c25 3230
0x00e0:  7b25 3232 6c6e 6725 3232 3a38 2e32 2c25
0x00f0:  3232 6c61 7425 3232 3a38 2e32 7d2c 2532
0x0100:  307b 2532 326c 6e67 2532 323a 382e 322c
0x0110:  2532 326c 6174 2532 323a 3130 2e32 7d5d
0x0120:  2c25 3232 636f 6f72 6474 7970 6525 3232
0x0130:  3a32 7d20 4854 5450 2f31 2e31 0d0a 486f
0x0140:  7374 3a20 3130 2e39 362e 3932 2e32 3132
0x0150:  3a37 3038 300d 0a55 7067 7261 6465 2d49
0x0160:  6e73 6563 7572 652d 5265 7175 6573 7473
0x0170:  3a20 310d 0a41 6363 6570 743a 2074 6578
0x0180:  742f 6874 6d6c 2c61 7070 6c69 6361 7469
0x0190:  6f6e 2f78 6874 6d6c 2b78 6d6c 2c61 7070
0x01a0:  6c69 6361 7469 6f6e 2f78 6d6c 3b71 3d30
0x01b0:  2e39 2c2a 2f2a 3b71 3d30 2e38 0d0a 5573
0x01c0:  6572 2d41 6765 6e74 3a20 4d6f 7a69 6c6c
0x01d0:  612f 352e 3020 284d 6163 696e 746f 7368
0x01e0:  3b20 496e 7465 6c20 4d61 6320 4f53 2058
0x01f0:  2031 305f 3133 5f36 2920 4170 706c 6557
0x0200:  6562 4b69 742f 3630 352e 312e 3135 2028
0x0210:  4b48 544d 4c2c 206c 696b 6520 4765 636b
0x0220:  6f29 2056 6572 7369 6f6e 2f31 322e 302e
0x0230:  3220 5361 6661 7269 2f36 3035 2e31 2e31
0x0240:  350d 0a41 6363 6570 742d 4c61 6e67 7561
0x0250:  6765 3a20 7a68 2d63 6e0d 0a41 6363 6570
0x0260:  742d 456e 636f 6469 6e67 3a20 677a 6970
0x0270:  2c20 6465 666c 6174 650d 0a43 6f6e 6e65
0x0280:  6374 696f 6e3a 206b 6565 702d 616c 6976
0x0290:  650d 0a0d 0a

我們來(lái)逐字節(jié)分析。

字節(jié)值 字節(jié)含義
0x4 IP版本為ipv4
0x5 首部長(zhǎng)度為5 * 4字節(jié)=20B
0x00 服務(wù)類型爸邢,現(xiàn)在基本都置為0
0x0295 總長(zhǎng)度為661字節(jié)樊卓,即整個(gè)包的長(zhǎng)度是661字節(jié)
0x0000 標(biāo)識(shí)。同一個(gè)數(shù)據(jù)報(bào)的唯一標(biāo)識(shí)杠河。當(dāng)IP數(shù)據(jù)報(bào)被拆分時(shí)碌尔,會(huì)復(fù)制到每一個(gè)數(shù)據(jù)中。
0x4000 3bit 標(biāo)志 + 13bit 片偏移券敌。3bit 標(biāo)志對(duì)應(yīng) R唾戚、DF、MF待诅。目前只有后兩位有效叹坦,DF位:為1表示不分片,為0表示分片卑雁。MF:為1表示“更多的片”募书,為0表示這是最后一片绪囱。13bit 片位移:本分片在原先數(shù)據(jù)報(bào)文中相對(duì)首位的偏移位。(需要再乘以8 )
0x36 生存時(shí)間TTL莹捡。IP報(bào)文所允許通過(guò)的路由器的最大數(shù)量鬼吵。每經(jīng)過(guò)一個(gè)路由器,TTL減1篮赢,當(dāng)為 0 時(shí)齿椅,路由器將該數(shù)據(jù)報(bào)丟棄。TTL 字段是由發(fā)送端初始設(shè)置一個(gè) 8 bit字段.推薦的初始值由分配數(shù)字 RFC 指定启泣。發(fā)送 ICMP 回顯應(yīng)答時(shí)經(jīng)常把 TTL 設(shè)為最大值 255涣脚。TTL可以防止數(shù)據(jù)報(bào)陷入路由循環(huán)。 此處為54.
0x06 協(xié)議類型种远。指出IP報(bào)文攜帶的數(shù)據(jù)使用的是哪種協(xié)議涩澡,以便目的主機(jī)的IP層能知道要將數(shù)據(jù)報(bào)上交到哪個(gè)進(jìn)程。TCP 的協(xié)議號(hào)為6坠敷,UDP 的協(xié)議號(hào)為17妙同。ICMP 的協(xié)議號(hào)為1,IGMP 的協(xié)議號(hào)為2膝迎。該 IP 報(bào)文攜帶的數(shù)據(jù)使用 TCP 協(xié)議粥帚,得到了驗(yàn)證。
0x623b 16bitIP首部校驗(yàn)和限次。
0xac17 ccdc 32bit源ip地址芒涡。
0x0a60 5cd4 32bit目的ip地址。

剩余的數(shù)據(jù)部分即為TCP協(xié)議相關(guān)的卖漫。TCP也是20B固定長(zhǎng)度+可變長(zhǎng)度部分费尽。

字節(jié)值 字節(jié)含義
0xdb9b 16bit源端口。56219
0x1ba8 16bit目的端口7080
0xa59a 46ce 32bit序列號(hào)羊始。2778351310
0x6d03 e87d 32bit確認(rèn)號(hào)旱幼。1828972669
0x8 4bit首部長(zhǎng)度,以4byte為單位突委。共8*4=32字節(jié)柏卤。因此TCP報(bào)文的可選長(zhǎng)度為32-20=12字節(jié)
0b000000 6bit保留位。目前置為0.
0b011000 6bitTCP標(biāo)志位匀油。從左到右依次是緊急 URG缘缚、確認(rèn) ACK、推送 PSH敌蚜、復(fù)位 RST桥滨、同步 SYN 、終止 FIN。ack有效该园,同時(shí)psh有效
0x1015 滑動(dòng)窗口大小酸舍,滑動(dòng)窗口即tcp接收緩沖區(qū)的大小,用于tcp擁塞控制里初。4117
0x0ee7 16bit校驗(yàn)和啃勉。
0x0000 緊急指針。僅在 URG = 1時(shí)才有意義双妨,它指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù)淮阐。當(dāng) URG = 1 時(shí),發(fā)送方 TCP 就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面刁品,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍是普通數(shù)據(jù)泣特。

可變長(zhǎng)度部分,協(xié)議如下:

字節(jié)值 字節(jié)含義
0x01 無(wú)操作
0x01 無(wú)操作
0x0402 表示支持SACK
0x080a 2e4c b2ef 0f20 3acf 時(shí)間戳挑随。Ts val=0x2e4c b2ef=776778479, ecr=0x0f20 3acf=253770447

剩下來(lái)的就是數(shù)據(jù)部分了状您。我們一行一行地看。因?yàn)閔ttp是字符流兜挨,所以我們先看一下ascii字符集膏孟,執(zhí)行命令:

man ascii

可以得到ascii碼,我們直接看十六進(jìn)制的結(jié)果:

ascii
行首地址 字節(jié)流 字符
0x0030 4745 5420 2f64 6174 613f 636d GE T /d at a? cm
0x0040 643d 4665 6e63 6532 4172 6561 266d 6574 d= Fe nc e2 Ar ea &m et
0x0050 613d 7b25 3232 6361 6c6c 6572 2532 323a a= {% 22 ca ll er %2 2:
0x0060 2532 3274 6573 7425 3232 2c25 3232 5472 %2 2t es t% 22 ,% 22 Tr
0x0070 6163 6549 6425 3232 3a25 3232 7465 7374 ac eI d% 22 :% 22 te st
0x0080 2532 327d 2672 6571 7565 7374 3d7b 2532 %2 2} &r eq ue st ={ %2
0x0090 3266 656e 6365 2532 323a 5b7b 2532 326c 2f en ce %2 2: [{ %2 2l
0x00a0 6e67 2532 323a 3130 2e32 2c25 3232 6c61 ng %2 2: 10 .2 ,% 22 la
0x00b0 7425 3232 3a31 302e 327d 2c25 3230 7b25 t% 22 :1 0. 2} ,% 20 {%
0x00c0 3232 6c6e 6725 3232 3a31 302e 322c 2532 22 ln g% 22 :1 0. 2, %2
0x00d0 326c 6174 2532 323a 382e 327d 2c25 3230 2l at %2 2: 8. 2} ,% 20
0x00e0 7b25 3232 6c6e 6725 3232 3a38 2e32 2c25 {% 22 ln g% 22 :8 .2 ,%
0x00f0 3232 6c61 7425 3232 3a38 2e32 7d2c 2532 22 la t% 22 :8 .2 }, %2
0x0100 307b 2532 326c 6e67 2532 323a 382e 322c 0{ %2 2l ng %2 2: 8. 2,
0x0110 2532 326c 6174 2532 323a 3130 2e32 7d5d %2 2l at %2 2: 10 .2 } ]
0x0120 2c25 3232 636f 6f72 6474 7970 6525 3232 ,% 22 co or dt yp e% 22
0x0130 3a32 7d20 4854 5450 2f31 2e31 0d0a 486f :2 } HT TP /1 .1 crnl Ho
0x0140 7374 3a20 3130 2e39 362e 3932 2e32 3132 st : 10 .9 6. 92 .2 12
0x0150 3a37 3038 300d 0a55 7067 7261 6465 2d49 :7 08 0cr nlU pg ra de -I
0x0160 6e73 6563 7572 652d 5265 7175 6573 7473 ns ec ur e- Re qu es ts
0x0170 3a20 310d 0a41 6363 6570 743a 2074 6578 : 1cr nlA cc ep t: t ex
0x0180 742f 6874 6d6c 2c61 7070 6c69 6361 7469 t/ ht ml ,a pp li ca ti
0x0190 6f6e 2f78 6874 6d6c 2b78 6d6c 2c61 7070 on /x ht ml +x ml ,a pp
0x01a0 6c69 6361 7469 6f6e 2f78 6d6c 3b71 3d30 li ca ti on /x ml ;q =0
0x01b0 2e39 2c2a 2f2a 3b71 3d30 2e38 0d0a 5573 .9 ,* /* ;q =0 .8 crnl Us
0x01c0 6572 2d41 6765 6e74 3a20 4d6f 7a69 6c6c er -A ge nt : Mo zi ll
0x01d0 612f 352e 3020 284d 6163 696e 746f 7368 a/ 5. 0 (M ac in to sh
0x01e0 3b20 496e 7465 6c20 4d61 6320 4f53 2058 ; In te l Ma c OS X
0x01f0 2031 305f 3133 5f36 2920 4170 706c 6557 1 0_ 13 _6 ) Ap pl eW
0x0200 6562 4b69 742f 3630 352e 312e 3135 2028 eb Ki t/ 60 5. 1. 15 (
0x0210 4b48 544d 4c2c 206c 696b 6520 4765 636b KH TM L, l i k e Ge ck
0x0220 6f29 2056 6572 7369 6f6e 2f31 322e 302e o) V er si o n /1 2. 0.
0x0230 3220 5361 6661 7269 2f36 3035 2e31 2e31 2 Sa fa ri /6 05 .1 .1
0x0240 350d 0a41 6363 6570 742d 4c61 6e67 7561 5cr nlA cc ep t- La ng ua
0x0250 6765 3a20 7a68 2d63 6e0d 0a41 6363 6570 ge : zh -c ncr nlA cc ep
0x0260 742d 456e 636f 6469 6e67 3a20 677a 6970 t- En co di ng : gz ip
0x0270 2c20 6465 666c 6174 650d 0a43 6f6e 6e65 , de fl at ecr nlC on ne
0x0280 6374 696f 6e3a 206b 6565 702d 616c 6976 ct io n: k ee p- al iv
0x0290 650d 0a0d 0a ecr nl cr nl

把上表的最后一列連起來(lái)拌汇,就是:

GET /data?cmd=Fence2Area&meta={%22caller%22:%22test%22,%22TraceId%22:%22test%22}&request={%22fence%22:[{%22lng%22:10.2,%22lat%22:10.2},%20{%22lng%22:10.2,%22lat%22:8.2},%20{%22lng%22:8.2,%22lat%22:8.2},%20{%22lng%22:8.2,%22lat%22:10.2}],%22coordtype%22:2} HTTP/1.1 
Host: 10.96.92.212:7080 
Upgrade-Insecure-Requests: 1 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.2 Safari/605.1.15 
Accept-Language: zh-cn 
Accept-Encoding: gzip, deflate 
Connection: keep-alive 
 

其中柒桑,cr nl表示回車,換行噪舀。

docker收到數(shù)據(jù)后魁淳,會(huì)回復(fù)一個(gè)ack包。第四個(gè)包的總長(zhǎng)度為661字節(jié)与倡,去掉IP頭部20字節(jié)界逛,TCP頭部固定部分20字節(jié),TCP頭部可選長(zhǎng)度為12字節(jié)纺座,共52字節(jié)息拜,因此TCP數(shù)據(jù)部分總長(zhǎng)度為661-52=609字節(jié)。另外比驻,序列號(hào)為2778351310.

再來(lái)看第5個(gè)包该溯,字節(jié)流如下:

0x0000:  4500 0034 d28b 4000 4006 8810 0a60 5cd4
0x0010:  ac17 ccdc 1ba8 db9b 6d03 e87d a59a 492f
0x0020:  8010 00ec e04e 0000 0101 080a 0f20 3af7
0x0030:  2e4c b2ef
字節(jié)值 字節(jié)含義
0x4 IP版本為ipv4
0x5 首部長(zhǎng)度為5 * 4字節(jié)=20B
0x00 服務(wù)類型岛抄,現(xiàn)在基本都置為0
0x0034 總長(zhǎng)度為52字節(jié)别惦,即整個(gè)包的長(zhǎng)度是52字節(jié)
0xd28b 標(biāo)識(shí)。同一個(gè)數(shù)據(jù)報(bào)的唯一標(biāo)識(shí)夫椭。當(dāng)IP數(shù)據(jù)報(bào)被拆分時(shí)掸掸,會(huì)復(fù)制到每一個(gè)數(shù)據(jù)中。
0x4000 3bit 標(biāo)志 + 13bit 片偏移。3bit 標(biāo)志對(duì)應(yīng) R扰付、DF堤撵、MF。目前只有后兩位有效羽莺,DF位:為1表示不分片实昨,為0表示分片。MF:為1表示“更多的片”盐固,為0表示這是最后一片荒给。13bit 片位移:本分片在原先數(shù)據(jù)報(bào)文中相對(duì)首位的偏移位。(需要再乘以8 )
0x40 生存時(shí)間TTL刁卜。IP報(bào)文所允許通過(guò)的路由器的最大數(shù)量志电。每經(jīng)過(guò)一個(gè)路由器,TTL減1蛔趴,當(dāng)為 0 時(shí)挑辆,路由器將該數(shù)據(jù)報(bào)丟棄。TTL 字段是由發(fā)送端初始設(shè)置一個(gè) 8 bit字段.推薦的初始值由分配數(shù)字 RFC 指定孝情。發(fā)送 ICMP 回顯應(yīng)答時(shí)經(jīng)常把 TTL 設(shè)為最大值 255鱼蝉。TTL可以防止數(shù)據(jù)報(bào)陷入路由循環(huán)。 此處為54.
0x06 協(xié)議類型咧叭。指出IP報(bào)文攜帶的數(shù)據(jù)使用的是哪種協(xié)議蚀乔,以便目的主機(jī)的IP層能知道要將數(shù)據(jù)報(bào)上交到哪個(gè)進(jìn)程。TCP 的協(xié)議號(hào)為6菲茬,UDP 的協(xié)議號(hào)為17吉挣。ICMP 的協(xié)議號(hào)為1,IGMP 的協(xié)議號(hào)為2婉弹。該 IP 報(bào)文攜帶的數(shù)據(jù)使用 TCP 協(xié)議睬魂,得到了驗(yàn)證。
0x8810 16bitIP首部校驗(yàn)和镀赌。
0x0a60 5cd4 32bit源ip地址氯哮。
0xac17 ccdc 32bit目的ip地址。

剩余的數(shù)據(jù)部分即為TCP協(xié)議相關(guān)的商佛。TCP也是20B固定長(zhǎng)度+可變長(zhǎng)度部分喉钢。

字節(jié)值 字節(jié)含義
0x1ba8 16bit源端口7080
0xdb9b 16bit目的端口。56219
0x6d03 e87d 32bit序列號(hào)良姆。1828972669
0xa59a 492f 32bit確認(rèn)號(hào)肠虽。2778351919. 第三個(gè)包的序列號(hào)為2778351310, 加上數(shù)據(jù)長(zhǎng)度609, 正好相等。
0x8 4bit首部長(zhǎng)度玛追,以4byte為單位税课。共8*4=32字節(jié)闲延。因此TCP報(bào)文的可選長(zhǎng)度為32-20=12字節(jié)
0b000000 6bit保留位。目前置為0.
0b010000 6bitTCP標(biāo)志位韩玩。從左到右依次是緊急 URG垒玲、確認(rèn) ACK、推送 PSH找颓、復(fù)位 RST合愈、同步 SYN 、終止 FIN击狮。ack有效
0x00ec 滑動(dòng)窗口大小想暗,滑動(dòng)窗口即tcp接收緩沖區(qū)的大小,用于tcp擁塞控制帘不。4117
0xe04e 16bit校驗(yàn)和说莫。
0x0000 緊急指針。僅在 URG = 1時(shí)才有意義寞焙,它指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù)储狭。當(dāng) URG = 1 時(shí),發(fā)送方 TCP 就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面捣郊,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍是普通數(shù)據(jù)辽狈。

可變長(zhǎng)度部分,協(xié)議如下:

字節(jié)值 字節(jié)含義
0x01 無(wú)操作
0x01 無(wú)操作
0x0402 表示支持SACK
0x080a 2e4c b2ef 0f20 3acf 時(shí)間戳呛牲。Ts val=253770487, ecr=776778479

數(shù)據(jù)部分為空刮萌,這個(gè)包僅為確認(rèn)包。

再來(lái)看第六個(gè)包娘扩,字節(jié)流如下:

0x0000:  4500 00f9 d28c 4000 4006 874a 0a60 5cd4
0x0010:  ac17 ccdc 1ba8 db9b 6d03 e87d a59a 492f
0x0020:  8018 00ec e113 0000 0101 080a 0f20 3af8
0x0030:  2e4c b2ef 4854 5450 2f31 2e31 2032 3030
0x0040:  204f 4b0d 0a41 6363 6573 732d 436f 6e74
0x0050:  726f 6c2d 416c 6c6f 772d 4f72 6967 696e
0x0060:  3a20 2a0d 0a44 6174 653a 2054 6875 2c20
0x0070:  3033 204a 616e 2032 3031 3920 3132 3a32
0x0080:  333a 3437 2047 4d54 0d0a 436f 6e74 656e
0x0090:  742d 4c65 6e67 7468 3a20 3438 0d0a 436f
0x00a0:  6e74 656e 742d 5479 7065 3a20 7465 7874
0x00b0:  2f70 6c61 696e 3b20 6368 6172 7365 743d
0x00c0:  7574 662d 380d 0a0d 0a7b 2264 6174 6122
0x00d0:  3a7b 2261 7265 6122 3a34 3837 3634 3133
0x00e0:  3535 3937 2e38 3432 3630 367d 2c22 6572
0x00f0:  7273 7472 223a 2222 7d
字節(jié)值 字節(jié)含義
0x4 IP版本為ipv4
0x5 首部長(zhǎng)度為5 * 4字節(jié)=20B
0x00 服務(wù)類型着茸,現(xiàn)在基本都置為0
0x00f9 總長(zhǎng)度為249字節(jié),即整個(gè)包的長(zhǎng)度是249字節(jié)
0xd28c 標(biāo)識(shí)琐旁。同一個(gè)數(shù)據(jù)報(bào)的唯一標(biāo)識(shí)涮阔。當(dāng)IP數(shù)據(jù)報(bào)被拆分時(shí),會(huì)復(fù)制到每一個(gè)數(shù)據(jù)中灰殴。
0x4000 3bit 標(biāo)志 + 13bit 片偏移敬特。3bit 標(biāo)志對(duì)應(yīng) R、DF牺陶、MF伟阔。目前只有后兩位有效,DF位:為1表示不分片掰伸,為0表示分片皱炉。MF:為1表示“更多的片”,為0表示這是最后一片碱工。13bit 片位移:本分片在原先數(shù)據(jù)報(bào)文中相對(duì)首位的偏移位娃承。(需要再乘以8 )
0x40 生存時(shí)間TTL。IP報(bào)文所允許通過(guò)的路由器的最大數(shù)量怕篷。每經(jīng)過(guò)一個(gè)路由器历筝,TTL減1,當(dāng)為 0 時(shí)廊谓,路由器將該數(shù)據(jù)報(bào)丟棄梳猪。TTL 字段是由發(fā)送端初始設(shè)置一個(gè) 8 bit字段.推薦的初始值由分配數(shù)字 RFC 指定。發(fā)送 ICMP 回顯應(yīng)答時(shí)經(jīng)常把 TTL 設(shè)為最大值 255蒸痹。TTL可以防止數(shù)據(jù)報(bào)陷入路由循環(huán)春弥。 此處為64.
0x06 協(xié)議類型。指出IP報(bào)文攜帶的數(shù)據(jù)使用的是哪種協(xié)議叠荠,以便目的主機(jī)的IP層能知道要將數(shù)據(jù)報(bào)上交到哪個(gè)進(jìn)程匿沛。TCP 的協(xié)議號(hào)為6,UDP 的協(xié)議號(hào)為17榛鼎。ICMP 的協(xié)議號(hào)為1逃呼,IGMP 的協(xié)議號(hào)為2。該 IP 報(bào)文攜帶的數(shù)據(jù)使用 TCP 協(xié)議者娱,得到了驗(yàn)證抡笼。
0x874a 16bitIP首部校驗(yàn)和。
0x0a60 5cd4 32bit源ip地址黄鳍。
0xac17 ccdc 32bit目的ip地址推姻。

剩余的數(shù)據(jù)部分即為TCP協(xié)議相關(guān)的。TCP也是20B固定長(zhǎng)度+可變長(zhǎng)度部分框沟。

字節(jié)值 字節(jié)含義
0x1ba8 16bit源端口7080
0xdb9b 16bit目的端口藏古。56219
0x6d03 e87d 32bit序列號(hào)。1828972669
0xa59a 492f 32bit確認(rèn)號(hào)忍燥。2778351919
0x8 4bit首部長(zhǎng)度校翔,以4byte為單位。共8*4=32字節(jié)灾前。因此TCP報(bào)文的可選長(zhǎng)度為32-20=12字節(jié)
0b000000 6bit保留位防症。目前置為0.
0b011000 6bitTCP標(biāo)志位。從左到右依次是緊急 URG哎甲、確認(rèn) ACK蔫敲、推送 PSH、復(fù)位 RST炭玫、同步 SYN 奈嘿、終止 FIN。ack有效吞加,同時(shí)psh有效
0x00ec 滑動(dòng)窗口大小裙犹,滑動(dòng)窗口即tcp接收緩沖區(qū)的大小尽狠,用于tcp擁塞控制。236
0xe113 16bit校驗(yàn)和叶圃。
0x0000 緊急指針袄膏。僅在 URG = 1時(shí)才有意義,它指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù)掺冠。當(dāng) URG = 1 時(shí)沉馆,發(fā)送方 TCP 就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍是普通數(shù)據(jù)德崭。

可變長(zhǎng)度部分斥黑,協(xié)議如下:

字節(jié)值 字節(jié)含義
0x01 無(wú)操作
0x01 無(wú)操作
0x0402 表示支持SACK
0x080a 0f20 3af8 2e4c b2ef 時(shí)間戳。Ts val=0x2e4c b2ef=253770488, ecr=0x0f20 3acf=776778479

剩下來(lái)的就是數(shù)據(jù)部分了眉厨。我們一行一行地看锌奴。

首地址 字節(jié)流 字符
0x0030 4854 5450 2f31 2e31 2032 3030 HTTP/1.1 200
0x0040 204f 4b0d 0a41 6363 6573 732d 436f 6e74 OK \r\n Access-Cont
0x0050 726f 6c2d 416c 6c6f 772d 4f72 6967 696e rol-Allow-Origin
0x0060 3a20 2a0d 0a44 6174 653a 2054 6875 2c20 : * \r\n Date: Thu,
0x0070 3033 204a 616e 2032 3031 3920 3132 3a32 03 Jan 2019 12:2
0x0080 333a 3437 2047 4d54 0d0a 436f 6e74 656e 3:47 GMT \r\n Conten
0x0090 742d 4c65 6e67 7468 3a20 3438 0d0a 436f t-Length: 48\r\n Co
0x00a0 6e74 656e 742d 5479 7065 3a20 7465 7874 ntent-Type: text
0x00b0 2f70 6c61 696e 3b20 6368 6172 7365 743d /plain; charset=
0x00c0 7574 662d 380d 0a0d 0a7b 2264 6174 6122 utf-8\r\n\r\n{"data"
0x00d0 3a7b 2261 7265 6122 3a34 3837 3634 3133 :{"area":4876413
0x00e0 3535 3937 2e38 3432 3630 367d 2c22 6572 5597.842606},"er
0x00f0 7273 7472 223a 2222 7d rstr":""}

把上表的最后一列連起來(lái),就是:

HTTP/1.1 200 OK 
Access-Control-Allow-Origin: * 
Date: Thu, 03 Jan 2019 12:23:47 GMT 
Content-Length: 48 
Content-Type: text/plain; charset=utf-8 
{"data":{"area":48764135597.842606},"errstr":""}

Content-Length: 48憾股,最后一行的長(zhǎng)度即為48個(gè)字節(jié)缨叫。

最后,第七個(gè)包荔燎,字節(jié)流如下:

0x0000:  4500 0034 0000 4000 3606 649c ac17 ccdc
0x0010:  0a60 5cd4 db9b 1ba8 a59a 492f 6d03 e942
0x0020:  8010 100f 1eb9 0000 0101 080a 2e4c b314
0x0030:  0f20 3af8
字節(jié)值 字節(jié)含義
0x4 IP版本為ipv4
0x5 首部長(zhǎng)度為5 * 4字節(jié)=20B
0x00 服務(wù)類型耻姥,現(xiàn)在基本都置為0
0x0034 總長(zhǎng)度為52字節(jié),即整個(gè)包的長(zhǎng)度是52字節(jié)
0x0000 標(biāo)識(shí)有咨。同一個(gè)數(shù)據(jù)報(bào)的唯一標(biāo)識(shí)琐簇。當(dāng)IP數(shù)據(jù)報(bào)被拆分時(shí),會(huì)復(fù)制到每一個(gè)數(shù)據(jù)中座享。
0x4000 3bit 標(biāo)志 + 13bit 片偏移婉商。3bit 標(biāo)志對(duì)應(yīng) R、DF渣叛、MF丈秩。目前只有后兩位有效,DF位:為1表示不分片淳衙,為0表示分片蘑秽。MF:為1表示“更多的片”,為0表示這是最后一片箫攀。13bit 片位移:本分片在原先數(shù)據(jù)報(bào)文中相對(duì)首位的偏移位肠牲。(需要再乘以8 )
0x36 生存時(shí)間TTL。IP報(bào)文所允許通過(guò)的路由器的最大數(shù)量靴跛。每經(jīng)過(guò)一個(gè)路由器缀雳,TTL減1,當(dāng)為 0 時(shí)梢睛,路由器將該數(shù)據(jù)報(bào)丟棄肥印。TTL 字段是由發(fā)送端初始設(shè)置一個(gè) 8 bit字段.推薦的初始值由分配數(shù)字 RFC 指定识椰。發(fā)送 ICMP 回顯應(yīng)答時(shí)經(jīng)常把 TTL 設(shè)為最大值 255。TTL可以防止數(shù)據(jù)報(bào)陷入路由循環(huán)深碱。 此處為54.
0x06 協(xié)議類型腹鹉。指出IP報(bào)文攜帶的數(shù)據(jù)使用的是哪種協(xié)議,以便目的主機(jī)的IP層能知道要將數(shù)據(jù)報(bào)上交到哪個(gè)進(jìn)程莹痢。TCP 的協(xié)議號(hào)為6,UDP 的協(xié)議號(hào)為17墓赴。ICMP 的協(xié)議號(hào)為1竞膳,IGMP 的協(xié)議號(hào)為2艇潭。該 IP 報(bào)文攜帶的數(shù)據(jù)使用 TCP 協(xié)議卸耘,得到了驗(yàn)證。
0x649c 16bitIP首部校驗(yàn)和声离。
0xac17 ccdc 32bit源ip地址章办。
0x0a60 5cd4 32bit目的ip地址锉走。

剩余的數(shù)據(jù)部分即為TCP協(xié)議相關(guān)的。TCP也是20B固定長(zhǎng)度+可變長(zhǎng)度部分藕届。

字節(jié)值 字節(jié)含義
0xdb9b 16bit源端口挪蹭。56219
0x1ba8 16bit目的端口7080
0xa59a 492f 32bit序列號(hào)。2778351919
0x6d03 e942 32bit確認(rèn)號(hào)號(hào)休偶。1828972866. 第六個(gè)包的序列號(hào)為1828972669, 加上數(shù)據(jù)長(zhǎng)度197, 正好相等
0x8 4bit首部長(zhǎng)度梁厉,以4byte為單位。共8*4=32字節(jié)踏兜。因此TCP報(bào)文的可選長(zhǎng)度為32-20=12字節(jié)
0b000000 6bit保留位词顾。目前置為0
0b010000 6bitTCP標(biāo)志位。從左到右依次是緊急 URG碱妆、確認(rèn) ACK肉盹、推送 PSH、復(fù)位 RST疹尾、同步 SYN 上忍、終止 FIN。ack有效
0x100f 滑動(dòng)窗口大小纳本,滑動(dòng)窗口即tcp接收緩沖區(qū)的大小睡雇,用于tcp擁塞控制。4111
0x1eb9 16bit校驗(yàn)和饮醇。
0x0000 緊急指針它抱。僅在 URG = 1時(shí)才有意義,它指出本報(bào)文段中的緊急數(shù)據(jù)的字節(jié)數(shù)朴艰。當(dāng) URG = 1 時(shí)观蓄,發(fā)送方 TCP 就把緊急數(shù)據(jù)插入到本報(bào)文段數(shù)據(jù)的最前面混移,而在緊急數(shù)據(jù)后面的數(shù)據(jù)仍是普通數(shù)據(jù)。

可變長(zhǎng)度部分侮穿,協(xié)議如下:

字節(jié)值 字節(jié)含義
0x01 無(wú)操作
0x01 無(wú)操作
0x080a 2e4c b314 0f20 3af8 時(shí)間戳歌径。Ts val=0x2e4c b314=776778516, ecr=0x0f20 3af8=253770488

至此,一次完整的http請(qǐng)求的報(bào)文就解析完了亲茅。感覺(jué)如何回铛,是不是很親切?

HTTP協(xié)議分析

上面我們把HTTP協(xié)議相關(guān)的數(shù)據(jù)給解構(gòu)了克锣,下面我將對(duì)照上面的數(shù)據(jù)拆解結(jié)果茵肃,一步步帶你深入理解HTTP協(xié)議。

整體介紹

HTTP(Hypertext Transfer Protocol)超文本傳輸協(xié)議袭祟,是在互聯(lián)網(wǎng)上進(jìn)行通信時(shí)使用的一種協(xié)議验残。說(shuō)得更形象一點(diǎn):HTTP是現(xiàn)代互聯(lián)網(wǎng)中使用的公共語(yǔ)言。它最著名的應(yīng)用是用在瀏覽器的服務(wù)器間的通信巾乳。

HTTP屬于應(yīng)用層協(xié)議您没,底層是靠TCP進(jìn)行可靠地信息傳輸。

HTTP層次

HTTP在傳輸一段報(bào)文時(shí)胆绊,會(huì)以的形式將報(bào)文數(shù)據(jù)的內(nèi)容通過(guò)一條打開(kāi)的TCP連接按序傳輸氨鹏。TCP接到上層應(yīng)用交給它的數(shù)據(jù)流之后,會(huì)按序?qū)?shù)據(jù)流打散成一個(gè)個(gè)的分段压状。再交到IP層喻犁,通過(guò)網(wǎng)絡(luò)進(jìn)行傳輸。另一端的接收方則相反何缓,它們將接收到的分段按序組裝好肢础,交給上層HTTP協(xié)議進(jìn)行處理。

tcp http structure

編碼

我們?cè)賮?lái)回顧一下:

url
原始url /data?cmd=Fence2Area&meta={"caller":"test","TraceId":"test"}&request={"fence":[{"lng":10.2,"lat":10.2}, {"lng":10.2,"lat":8.2}, {"lng":8.2,"lat":8.2}, {"lng":8.2,"lat":10.2}],"coordtype":2}
編碼后url /data?cmd=Fence2Area&meta={%22caller%22:%22test%22,%22TraceId%22:%22test%22}&request={%22fence%22:[{%22lng%22:10.2,%22lat%22:10.2},%20{%22lng%22:10.2,%22lat%22:8.2},%20{%22lng%22:8.2,%22lat%22:8.2},%20{%22lng%22:8.2,%22lat%22:10.2}],%22coordtype%22:2}

在之前的報(bào)文拆解過(guò)程中碌廓,我們看到多了很多%22传轰,其實(shí),0x22是單引號(hào)"的ascii值谷婆,

一方面慨蛙,URL描述的資源為了能通過(guò)其他各種協(xié)議傳送,但是有些協(xié)議在傳輸過(guò)程中會(huì)剝?nèi)ヒ恍┨囟ǖ淖址涂妫涣硪环矫嫫谄叮琔RL還是可讀的,所以那些不可打印的字符就不能在URL中使用了异袄,比如空格通砍;最后,URL還得是完整的,它需要支持所有語(yǔ)言的字符封孙。

總之迹冤,基于很多原因,URL設(shè)計(jì)者將US-ASCII碼和其轉(zhuǎn)義序列集成到URL中虎忌,通過(guò)轉(zhuǎn)義序列泡徙,就可以用US-ASCII字符集的有限子集對(duì)任意字符或數(shù)據(jù)進(jìn)行編碼了。

轉(zhuǎn)義的方法:百分號(hào)(%)后跟著兩個(gè)表示ASCII碼的十六進(jìn)制數(shù)膜蠢。比如:

轉(zhuǎn)義法

所以上面在瀏覽器發(fā)送給服務(wù)器的URL進(jìn)行了非“安全字符”編碼堪藐,也就不奇怪了吧?

url保留及受限的字符

在URL中挑围,當(dāng)上面的保留字符用在保留用途之外的場(chǎng)合時(shí)礁竞,需要對(duì)URL進(jìn)行編碼。

MIME類型

響應(yīng)數(shù)據(jù)中贪惹,我們注意到有一個(gè)首部:

Content-Type: text/plain; charset=utf-8

互聯(lián)網(wǎng)上有數(shù)千種不同的數(shù)據(jù)類型苏章,HTTP給每種對(duì)象都打上了MIME(Multipurpose Internet Media Extension, 多用途因特網(wǎng)郵件擴(kuò)展)標(biāo)簽寂嘉,也就是響應(yīng)數(shù)據(jù)中的Content-Type. MIME本來(lái)是用在郵件協(xié)議中的奏瞬,后來(lái)被移植到了HTTP中。瀏覽器從服務(wù)器上取回了一個(gè)對(duì)象時(shí)泉孩,會(huì)去查看MIME類型硼端,從而得知如何處理這種對(duì)象,是該展示圖片寓搬,還是調(diào)用聲卡播放聲音珍昨。MIME通過(guò)斜杠來(lái)標(biāo)識(shí)對(duì)象的主類型和其中的特定的子類型,下表展示了一些常見(jiàn)的類型句喷,其中的實(shí)體主體是指body部分:

MIME類型

URI/URL/URN

URI(Uniform Resource Identifier, 統(tǒng)一資源標(biāo)識(shí)符)表示服務(wù)器資源镣典,URL(Uniform Resource Locator, 統(tǒng)一資源定位符)和URN(Uniform Resource Name, 統(tǒng)一資源名)是URI的具體實(shí)現(xiàn)。URI是一個(gè)通用的概念唾琼,由兩個(gè)主要的子集URL和URN構(gòu)成兄春,URL通過(guò)位置、URN通過(guò)名字來(lái)標(biāo)識(shí)資源锡溯。

URL定義了資源的位置赶舆,表示資源的實(shí)際地址,在使用URL的過(guò)程中祭饭,如果URL背后的資源發(fā)生了位置移動(dòng)芜茵,訪問(wèn)者就找不到它了。這個(gè)時(shí)候就要用到URN了倡蝙,它給定資源一個(gè)名字九串,無(wú)論它移動(dòng)到哪里,都可以通過(guò)這個(gè)名字來(lái)訪問(wèn)到它寺鸥,簡(jiǎn)直完美蒸辆!

URL通常的格式是:

協(xié)議方案+服務(wù)器地址+具體的資源路徑

協(xié)議方案(scheme)征炼,如 http, ftp,告知web客戶端怎樣訪問(wèn)資源)躬贡;服務(wù)器地址谆奥,如 www.oreilly.com; 具體的資源路徑,如 index.html.

URL舉例

HTTP方法

HTTP支持幾種不同的請(qǐng)求方法拂玻,每種方法對(duì)服務(wù)器要求的動(dòng)作不同酸些,如下圖是幾種常見(jiàn)的方法:

常見(jiàn)的http方法

HEAD方法只獲取頭部,不獲取數(shù)據(jù)部分檐蚜。通過(guò)頭部可以獲取比如資源的類型(Content-Type)魄懂、資源的長(zhǎng)度(Content-Length)這些信息。這樣闯第,客戶端可以獲取即將請(qǐng)求資源的一些情況市栗,可以做到心中有數(shù)。

POST用于向服務(wù)器發(fā)送數(shù)據(jù)咳短,常見(jiàn)的是提交表單填帽;PUT用于向服務(wù)器上的資源存儲(chǔ)數(shù)據(jù)。

狀態(tài)碼

每條HTTP的響應(yīng)報(bào)文都會(huì)帶上一個(gè)三位數(shù)字的狀態(tài)碼和一條解釋性的“原因短語(yǔ)”咙好,通知客戶端本次請(qǐng)求的狀態(tài)篡腌,幫助客戶端快速理解事務(wù)處理結(jié)果,最常見(jiàn)的是:

200 OK 
404 Not Found
500 Internal Server Error

我們平時(shí)使用瀏覽器的時(shí)候勾效,很多的錯(cuò)誤碼其實(shí)是由瀏覽器處理的嘹悼,我們感知不到。但是404 Not Found會(huì)穿透重重迷霧层宫,來(lái)到我們面前杨伙,為何?那是因?yàn)樗麑?duì)我們愛(ài)的深沉懊韧取限匣!

客戶端可以據(jù)此狀態(tài)碼,決定下一步的行動(dòng)(如重定向等)哮奇。

三位數(shù)字的第一位表示分類:

http狀態(tài)分類

報(bào)文格式

HTTP報(bào)文實(shí)際上是由一行行的字符串組成的膛腐,每行字符串的末尾用\r\n分隔,人類可以很方便的閱讀鼎俘。順便說(shuō)一句哲身,不是所有的協(xié)議都對(duì)人類這么友好的,像thrift協(xié)議贸伐,直接甩一堆字節(jié)給你勘天,告訴你說(shuō)0x0001表示調(diào)用方法,諸如此類的,你只能對(duì)著一個(gè)十六進(jìn)制的數(shù)據(jù)塊一個(gè)個(gè)地去“解碼”脯丝。不可能像HTTP協(xié)議這樣商膊,直接將字符編碼,人類可以直接讀懂宠进。

舉個(gè)簡(jiǎn)單的請(qǐng)求報(bào)文和響應(yīng)報(bào)文的格式的例子:

請(qǐng)求響應(yīng)報(bào)文示例

實(shí)際上晕拆,請(qǐng)求報(bào)文也是可以有body(主體)部分的。請(qǐng)求報(bào)文是由請(qǐng)求行(request line)材蹬、請(qǐng)求頭部(header)实幕、空行、請(qǐng)求數(shù)據(jù)四個(gè)部分組成堤器。唯一要注意的一點(diǎn)就是昆庇,請(qǐng)求報(bào)文即使body部分是空的,請(qǐng)求頭部后的回車換行符也是必須要有的闸溃。

請(qǐng)求報(bào)文格式

響應(yīng)報(bào)文的格式和請(qǐng)求報(bào)文的格式類似:

響應(yīng)報(bào)文格式

請(qǐng)求報(bào)文整吆、響應(yīng)報(bào)文的起始行和響應(yīng)頭部里的字段都是文本化、結(jié)構(gòu)化的辉川。而請(qǐng)求body卻可以包含任意二進(jìn)制數(shù)據(jù)(如圖片表蝙、視頻、軟件等)员串,當(dāng)然也可以包含文本勇哗。

有些首部是通用的昼扛,有些則是請(qǐng)求或者響應(yīng)報(bào)文才會(huì)有的寸齐。

首部 屬性 含義
Date 通用 Thu, 03 Jan 2019 12:23:47 GMT 報(bào)文構(gòu)建的時(shí)間
Accept 請(qǐng)求報(bào)文 text/html,application/xhtml+xml,application/xm 客戶端能接收的數(shù)據(jù)類型
Content-Type 通用 Content-Type: text/plain; charset=utf-8 報(bào)文中的body部分的數(shù)據(jù)類型。注意抄谐,若是請(qǐng)求報(bào)文中也有數(shù)據(jù)部分渺鹦,也是需要此字段的

順便提一下, 用telnet直連服務(wù)器的http端口蛹含,telnet命令會(huì)建立一條TCP通道毅厚,然后就可以通過(guò)這個(gè)通道直接發(fā)送HTTP請(qǐng)求數(shù)據(jù),獲取響應(yīng)數(shù)據(jù)了浦箱。

用telnet進(jìn)行http對(duì)話

HTTP協(xié)議進(jìn)階

代理

HTTP的代理服務(wù)器既是Web服務(wù)器吸耿,又是Web客戶端。

HTTP代理

使用代理可以“接觸”到所有流過(guò)的HTTP流量酷窥,代理可以對(duì)其進(jìn)行監(jiān)視和修改咽安。常見(jiàn)的就是對(duì)兒童過(guò)濾一些“成人”內(nèi)容;網(wǎng)絡(luò)工程師會(huì)利用代理服務(wù)器來(lái)提高安全性蓬推,它可以限制哪些應(yīng)用層的協(xié)議數(shù)據(jù)可以通過(guò)妆棒,過(guò)濾“病毒”等數(shù)據(jù);代理可以存儲(chǔ)緩存的文件,直接返回給訪問(wèn)者糕珊,無(wú)需請(qǐng)求原始的服務(wù)器資源动分;對(duì)于訪問(wèn)慢速網(wǎng)絡(luò)上的公共內(nèi)容時(shí),可以假扮服務(wù)器提供服務(wù)红选,從而提高訪問(wèn)速度澜公;這被稱為反向代理;可以作為內(nèi)容路由器喇肋,如對(duì)付費(fèi)用戶玛瘸,則將請(qǐng)求導(dǎo)到緩存服務(wù)器,提高訪問(wèn)速度苟蹈;可以將頁(yè)面的語(yǔ)言轉(zhuǎn)換到與客戶端相匹配糊渊,這稱為內(nèi)容轉(zhuǎn)碼器; 匿名代理會(huì)主動(dòng)從HTTP報(bào)文中刪除身份相關(guān)的信息,如User-Agent, Cookie等字段慧脱。

現(xiàn)實(shí)中渺绒,請(qǐng)求通過(guò)以下幾種方式打到代理服務(wù)器上去:

代理獲取流量的方式

報(bào)文每經(jīng)過(guò)一個(gè)中間點(diǎn)(代理或網(wǎng)關(guān)),都需要在首部via字段的末尾插入一個(gè)可以代表本節(jié)點(diǎn)的獨(dú)特的字符串菱鸥,包含實(shí)現(xiàn)的協(xié)議版本和主機(jī)地址宗兼。注意圖中的via字段。

via字段

請(qǐng)求和響應(yīng)的報(bào)文傳輸路徑通常都是一致的氮采,只不過(guò)方向是相反的殷绍。因此,響應(yīng)報(bào)文上的via字段表示的中間節(jié)點(diǎn)的順序是剛好相反的鹊漠。

緩存

當(dāng)有很多請(qǐng)求訪問(wèn)同一個(gè)頁(yè)面時(shí)主到,服務(wù)器會(huì)多次傳輸同一份數(shù)據(jù),這些數(shù)據(jù)重復(fù)地在網(wǎng)絡(luò)中傳輸著躯概,消耗著大量帶寬登钥。如果將這些數(shù)據(jù)緩存下來(lái),就可以提高響應(yīng)速度娶靡,節(jié)省網(wǎng)絡(luò)帶寬了牧牢。

大部分緩存只有在客戶端發(fā)起請(qǐng)求,并且副本已經(jīng)比較舊的情況下才會(huì)對(duì)副本的新鮮度進(jìn)行檢測(cè)姿锭。最常用的請(qǐng)求首部是If-Modified-Since, 如果在xx時(shí)間(此時(shí)間即為If-Modified-Since的值)之后內(nèi)容沒(méi)有變化塔鳍,服務(wù)器會(huì)回應(yīng)一個(gè)304 Not Modified. 否則,服務(wù)器會(huì)正常響應(yīng)呻此,并返回原始的文件數(shù)據(jù)轮纫,而這個(gè)過(guò)程中被稱為再驗(yàn)證命中

再驗(yàn)證可能出現(xiàn)命中或未命中的情況趾诗。未命中時(shí)蜡感,服務(wù)器回復(fù)200 OK蹬蚁,并且返回完整的數(shù)據(jù);命中時(shí)郑兴,服務(wù)器回復(fù)304 Not Modified; 還有一種情況犀斋,緩存被刪除了,那么根據(jù)響應(yīng)狀態(tài)碼情连,緩存服務(wù)器也會(huì)刪除自己緩存的副本叽粹。

順帶提一句,若要在項(xiàng)目中使用緩存却舀,就一定要關(guān)注緩存命中比例虫几。若命中比例不高,就要重新考慮設(shè)置緩存的必要性了挽拔。

緩存服務(wù)器返回響應(yīng)的時(shí)候辆脸,是基于已緩存的服務(wù)器響應(yīng)的首部,再對(duì)一些首部字段做一些微調(diào)螃诅。比如向其中插入新鮮度信息(如Age, Expires首部等)啡氢,而且通常會(huì)包含一個(gè)via首部來(lái)說(shuō)明緩存是由一個(gè)緩存代理提供的。注意术裸,這時(shí)不要修改Date字段倘是,它表示原始服務(wù)器最初構(gòu)建這條響應(yīng)的日期。

HTTP通過(guò)文檔過(guò)期機(jī)制服務(wù)器再驗(yàn)證機(jī)制保持已緩存數(shù)據(jù)和服務(wù)器間的數(shù)據(jù)充分一致袭艺。

文檔過(guò)期通過(guò)如下首部字段來(lái)表示緩存的有效期:

緩存有效期

當(dāng)上面兩個(gè)字段暗示的過(guò)期時(shí)間已到搀崭,需要向服務(wù)器再次驗(yàn)證文檔的新鮮度。如果這時(shí)緩存仍和服務(wù)器上的原始文檔一致猾编,緩存只需要更新頭部的相關(guān)字段瘤睹。如上表中提到的Expires字段等。

為了更好的節(jié)省網(wǎng)絡(luò)流量袍镀,緩存服務(wù)器可以通過(guò)相關(guān)首部向原始服務(wù)器發(fā)送一個(gè)條件GET請(qǐng)求, 這樣只有在緩存真正過(guò)期的情況下默蚌,才會(huì)返回原始的文檔冻晤,否則只會(huì)返回相關(guān)的首部苇羡。條件GET請(qǐng)求會(huì)用到如下的字段:

緩存條件GET

cookie

cookie是服務(wù)器“貼在”客戶端身上的標(biāo)簽,由客戶端維護(hù)的狀態(tài)片段鼻弧,并且只會(huì)回送給合適的站點(diǎn)设江。

有兩類cookie: 會(huì)話cookie、持久cookie. 會(huì)話cookie在退出瀏覽器后就被刪除了攘轩;而持久cookie則保存在硬盤中叉存,計(jì)算機(jī)重啟后仍然存在。

服務(wù)器在給客戶端的響應(yīng)字段首部加上Set-cookieSet-cookie2, 值為名字=值的列表度帮,即可以包含多個(gè)字段歼捏。當(dāng)下次瀏覽器再次訪問(wèn)到相同的網(wǎng)站時(shí)稿存,會(huì)將這些字段通過(guò)Cookie帶上。cookie中保留的內(nèi)容是服務(wù)器給此客戶端打的標(biāo)簽瞳秽,方便服務(wù)進(jìn)行追蹤的識(shí)別碼瓣履。瀏覽器會(huì)將cookie以特定的格式存儲(chǔ)在特定的文件中。

瀏覽器只會(huì)向產(chǎn)生這條cookie的站點(diǎn)發(fā)生cookie. Set-cookie字段的值會(huì)包含domain這個(gè)字段练俐,告知瀏覽器可以把這條cookie發(fā)送給給相關(guān)的匹配的站點(diǎn)袖迎。path字段也是相似的功能。如i瀏覽器收到如下的cookie:

Set-cookie: user="mary"; domain="stefno.com"

那么瀏覽器在訪問(wèn)任意以stefno.com結(jié)尾的站點(diǎn)都會(huì)發(fā)送:

Cookie: user="mary"

實(shí)體和編碼

響應(yīng)報(bào)文中的body部分傳輸?shù)臄?shù)據(jù)本質(zhì)上都是二進(jìn)制腺晾。我們從上面的報(bào)文數(shù)據(jù)也可以看出來(lái)燕锥,都是用十六進(jìn)制數(shù)來(lái)表示,關(guān)鍵是怎么解釋這塊內(nèi)容悯蝉。如果Content-Type定義是text/plain, 那說(shuō)明body內(nèi)容就是文本归形,我們直接按文本編碼來(lái)解釋;如果Content-Type定義是image/png, 說(shuō)明body部分是一幅圖片鼻由,那我們就按圖片的格式去解釋數(shù)據(jù)连霉。

Content-Length標(biāo)示報(bào)文主體部分的數(shù)據(jù)長(zhǎng)度大小,如果內(nèi)容是壓縮的嗡靡,那它表示的就是壓縮后的大小跺撼。另外,Content-Length在長(zhǎng)連接的情況下讨彼,可以對(duì)多個(gè)報(bào)文進(jìn)行正確地分段歉井。所以,如果沒(méi)有采用分塊編碼哈误,響應(yīng)數(shù)據(jù)中必須帶上Content-Length字段哩至。分塊編碼的情形中,數(shù)據(jù)被拆分成很多小塊蜜自,每塊都有大小說(shuō)明菩貌。因此,任何帶有主體部分的報(bào)文(請(qǐng)求或是響應(yīng))都應(yīng)帶上正確的Content-Length首部重荠。

HTTP的早期版本采用關(guān)閉連接的方式來(lái)劃定報(bào)文的結(jié)束箭阶。這帶來(lái)的問(wèn)題是顯而易見(jiàn)的:客戶端并不能分清是因?yàn)榉?wù)器正常結(jié)束還是中途崩潰了。這里戈鲁,如果是客戶端用關(guān)閉來(lái)表示請(qǐng)求報(bào)文主體部分的結(jié)束仇参,是不可取的,因?yàn)殛P(guān)閉之后婆殿,就無(wú)法獲取服務(wù)器的響應(yīng)了诈乒。當(dāng)然,客戶端可以采用半關(guān)閉的方式婆芦,只關(guān)閉數(shù)據(jù)發(fā)送方向怕磨,但是很多服務(wù)器是不識(shí)別的喂饥,會(huì)把半關(guān)閉當(dāng)成客戶端要成服務(wù)器斷開(kāi)來(lái)處理。

HTTP報(bào)文在傳輸?shù)倪^(guò)程中可能會(huì)遭到代理或是其他通信實(shí)體的無(wú)意修改肠鲫,為了讓接收方知道這種情況仰泻,服務(wù)器會(huì)對(duì)body部分作一個(gè)md5, 并把值放到Content-MD5這個(gè)字段中。但是滩届,如果中間的代理即修改了報(bào)文主體集侯,又修改了md5, 就不好檢測(cè)了。因此規(guī)定代理是不能修改Content-MD5首部的帜消。這樣棠枉,客戶端在收到數(shù)據(jù)后,先進(jìn)行解碼泡挺,再算出md5, 并與Content-MD5首部進(jìn)行比較辈讶。這主要是防止代理對(duì)報(bào)文進(jìn)行了無(wú)意的改動(dòng)。

HTTP在發(fā)送內(nèi)容之前需要對(duì)其進(jìn)行編碼娄猫,它是對(duì)報(bào)文主體進(jìn)行的可逆變換贱除。比如將報(bào)文用gzip格式進(jìn)行壓縮,減少傳輸時(shí)間媳溺。常見(jiàn)的編碼類型如下:

編碼類型

當(dāng)然月幌,客戶端為了避免服務(wù)器返回自己不能解碼的數(shù)據(jù),請(qǐng)求的時(shí)候悬蔽,會(huì)在Accept-Encoding首部里帶上自己支持的編碼方式扯躺。如果不傳輸?shù)脑挘J(rèn)可以接受任何編碼方式蝎困。

上面提到的編碼是內(nèi)容編碼录语,它只是在響應(yīng)報(bào)文的主體報(bào)文將原始數(shù)據(jù)進(jìn)行編碼,改變的是內(nèi)容的格式禾乘。還有另一種編碼:傳輸編碼澎埠。它與內(nèi)容無(wú)關(guān),它是為了改變報(bào)文數(shù)據(jù)在網(wǎng)絡(luò)上傳輸?shù)姆绞绞寂骸鬏斁幋a是在HTTP 1.1中引入的一個(gè)新特性蒲稳。

通常,服務(wù)器需要先生成數(shù)據(jù)鳄虱,再進(jìn)行傳輸弟塞,這時(shí),可以計(jì)算數(shù)據(jù)的長(zhǎng)度拙已,并將其編碼到Content-Length中。但是摧冀,有時(shí)硼讽,內(nèi)容是動(dòng)態(tài)生成的,服務(wù)器希望在數(shù)據(jù)生成之前就開(kāi)始傳輸垮斯,這時(shí)耐朴,是沒(méi)有辦法知道數(shù)據(jù)大小的。這種情況下腾降,就要用到傳輸編碼來(lái)標(biāo)注數(shù)據(jù)的結(jié)束的。

HTTP協(xié)議中通過(guò)如下兩個(gè)首部來(lái)描述和控制傳輸編碼:

字段 含義 典型值
Transfer-Encoding 發(fā)送方告知接收方,我方已經(jīng)進(jìn)行了何種傳輸編碼 chuncked 分塊編碼
TE 請(qǐng)求方告知服務(wù)器可以用哪種傳輸編碼 trailers, chuncked 接受分塊編碼潮罪,并且愿意接受在報(bào)文結(jié)尾上的拖掛

分塊編碼的報(bào)文形式是這樣的:

分塊編碼

每個(gè)分塊包含一個(gè)長(zhǎng)度值(十六進(jìn)制,字節(jié)數(shù))和該分塊的數(shù)據(jù)领斥。<CR><LF>用于區(qū)隔長(zhǎng)度值和數(shù)據(jù)嫉到。長(zhǎng)度值不包含分塊中的任何<CR><LF>序列。最后一個(gè)分塊月洛,用長(zhǎng)度值0來(lái)表示結(jié)束何恶。注意報(bào)文首部包含一個(gè)Trailer: Content-MD5, 所以在緊跟著最后一個(gè)報(bào)文結(jié)束之后,就是一個(gè)拖掛嚼黔。其他如细层,Content-Length, Trailer, Transfer-Encoding也可以作為拖掛。

內(nèi)容編碼和傳輸編碼是可以結(jié)合起來(lái)使用的唬涧。

內(nèi)容編碼和傳輸編碼結(jié)合

國(guó)際化支持

HTTP為了支持國(guó)際化的內(nèi)容疫赎,客戶端要告知服務(wù)器自己能理解的何種語(yǔ)言,以及瀏覽器上安裝了何種字母表編碼算法碎节。這通過(guò)Accept-CharsetAccept-Language首部實(shí)現(xiàn)虚缎。

比如:

Accept-Language: fr, en;q=0.8
Accept-Charset: iso-8859-1, utf-8

表示:客戶端接受法語(yǔ)(fr, 優(yōu)先級(jí)默認(rèn)為1.0)、英語(yǔ)(en, 優(yōu)先級(jí)為0.8)钓株,支持iso-8859-1, utf-8兩種字符集編碼实牡。服務(wù)器則會(huì)在Content-Type首部里放上charset.

本質(zhì)上,HTTP報(bào)文的body部分存放的就是一串二進(jìn)制碼轴合,我們先把二進(jìn)制碼轉(zhuǎn)換成字符代碼(如ascii是一個(gè)字節(jié)表示一個(gè)字符创坞,而utf-8則表示一個(gè)字符的字節(jié)數(shù)不定,每個(gè)字符1~6個(gè)字節(jié))受葛,之后题涨,用字符代碼去字符集中找到對(duì)應(yīng)的元素。

比較常見(jiàn)的字符集是US-ASCII: 這個(gè)字符集是所有字符集的始祖总滩,早在1968年就發(fā)布了標(biāo)準(zhǔn)纲堵。ASCII碼的代碼值從0到127, 只需要7個(gè)bit位就可以覆蓋代碼空間。HTTP報(bào)文的首部闰渔、URL使用的字符集就是ASCII碼席函。可以再看下上文報(bào)文分析部分的acsii碼集冈涧。

US-ASCII是把每個(gè)字符編碼成固定的7位二進(jìn)制值茂附。UTF-8則是無(wú)固定的編碼方案正蛙。第一個(gè)字節(jié)的高位用來(lái)表示編碼后的字符所用的字節(jié)數(shù)(如果所用的字節(jié)數(shù)是5,則第一個(gè)字節(jié)前5bit都是1营曼,第6bit是0)乒验,所需的后續(xù)的字節(jié)都含有6位的代碼值,前兩個(gè)bit位是用10標(biāo)識(shí)蒂阱。

utf-8編碼

舉個(gè)例子锻全,漢字“嚴(yán)”的Unicode編碼為4E25(100111000100101), 共有15位,落在上表中的第三行录煤,因此“嚴(yán)”的編碼就需要三個(gè)字節(jié)鳄厌。將100111000100101填入上表中的c位即可。因此辐赞,嚴(yán)的UTF-8編碼是11100100 10111000 10100101部翘,轉(zhuǎn)換成十六進(jìn)制就是E4B8A5. 比如我在谷歌搜索框里搜索“嚴(yán)”字,google發(fā)出的請(qǐng)求如下:

https://www.google.com.hk/search?q=%E4%B8%A5&oq=%E4%B8%A5&aqs=chrome..69i57j0l5.3802j0j4&sourceid=chrome&ie=UTF-8&gws_rd=cr

q=%E4%B8%A5這個(gè)就是搜索的詞了响委。

重定向與負(fù)載均衡

Web內(nèi)容通常分散地分布在很多地方新思,這可以防止“單點(diǎn)故障”,萬(wàn)一某個(gè)地方發(fā)生地震了赘风,機(jī)房被毀了夹囚,那還有其他地方的機(jī)房可以提供服務(wù)。一般都會(huì)有所謂的“雙活”邀窃,“多活”荸哟,所謂狡兔三窟嘛。

這樣瞬捕,用戶的請(qǐng)求會(huì)根據(jù)負(fù)載均衡的原則鞍历,被重定向到它應(yīng)該去的地方。

HTTP重定向

服務(wù)器收到客戶端請(qǐng)求后肪虎,向客戶端返回一條帶有狀態(tài)碼302重定向的報(bào)文劣砍,告訴他們應(yīng)該去其他的地方試試。web站點(diǎn)將重定向看成一種簡(jiǎn)單的負(fù)載均衡策略來(lái)使用扇救,重定向服務(wù)器找到可用的負(fù)載最小的機(jī)器刑枝,由于服務(wù)器知道客戶端的地址,理論上來(lái)說(shuō)迅腔,可以做到最優(yōu)的重定向選擇装畅。

當(dāng)然,缺點(diǎn)也是顯而易見(jiàn)的沧烈,由于客戶端要發(fā)送兩次請(qǐng)求掠兄,因此會(huì)增加耗時(shí)。

DNS重定向

DNS將幾個(gè)IP地址關(guān)聯(lián)到一個(gè)域上,采用算法決定返回的IP地址徽千∩环眩可以是簡(jiǎn)單的輪轉(zhuǎn)汤锨;也可以是更高級(jí)的算法双抽,如返回負(fù)載最輕的服務(wù)器的IP地址,稱為負(fù)載均衡算法闲礼;如果考慮地理位置牍汹,返回給客戶端最近位置的地址,稱為鄰接路由算法柬泽;還有一種是繞過(guò)出現(xiàn)故障的地址慎菲,稱為故障屏蔽算法

DNS服務(wù)器總是會(huì)返回所有的IP地址锨并,但是DNS客戶端一般只會(huì)使用第一個(gè)IP地址露该,而且會(huì)緩存下來(lái),之后會(huì)一直用這個(gè)地址第煮。所以解幼,DNS輪轉(zhuǎn)通常不會(huì)平衡單個(gè)客戶端的負(fù)載。但是包警,由于DNS服務(wù)器對(duì)于不同的請(qǐng)求撵摆,總是會(huì)返回輪轉(zhuǎn)后的IP地址列表,因此害晦,會(huì)把負(fù)載分散到多個(gè)客戶端特铝。

HTTP連接

HTTP連接是HTTP報(bào)文傳輸?shù)年P(guān)鍵通道。

并行連接

對(duì)于一個(gè)頁(yè)面上同時(shí)出現(xiàn)多個(gè)對(duì)象的時(shí)候壹瘟,如果瀏覽器并行地打開(kāi)多個(gè)連接鲫剿,同時(shí)去獲取這些對(duì)象,多個(gè)連接的TCP握手時(shí)延可以進(jìn)行重疊稻轨,速度會(huì)快起來(lái)灵莲。

如一個(gè)包含3張圖片的頁(yè)面,瀏覽器要發(fā)送4次HTTP請(qǐng)求來(lái)獲取頁(yè)面澄者。1個(gè)用于頂層的HTML頁(yè)面笆呆,3個(gè)用于圖片。如果采用串行方式粱挡,那么連接時(shí)延會(huì)進(jìn)行疊加赠幕。

串行連接

采用并行連接之后:

并行連接

但是并行連接也不絕對(duì)提升速度,如果一個(gè)頁(yè)面有數(shù)百個(gè)內(nèi)嵌對(duì)象询筏,那要啟動(dòng)數(shù)百個(gè)連接榕堰,對(duì)服務(wù)器的性能也是非常大的挑戰(zhàn)。所以,通常瀏覽器會(huì)限制并行連接的總數(shù)據(jù)在一個(gè)較小的值逆屡,通常是4個(gè)圾旨,而且服務(wù)端可以隨意關(guān)閉客戶端超量的連接。

另一方面魏蔗,如果客戶端網(wǎng)絡(luò)帶寬較小砍的,每個(gè)連接都會(huì)去爭(zhēng)搶有限的帶寬,每個(gè)連接都會(huì)獲取較小的速度莺治,即每個(gè)對(duì)象都會(huì)以較小的速度去加載廓鞠。這樣,并行連接帶來(lái)的速度提升就會(huì)比較小谣旁,甚至沒(méi)有提升床佳。

持久連接

HTTP keep-alive機(jī)制

我們知道HTTP請(qǐng)求是“請(qǐng)求-應(yīng)答”模式,每次請(qǐng)求-應(yīng)答都要新建一個(gè)連接榄审,完成之后要斷開(kāi)連接砌们。HTTP是無(wú)狀態(tài)的,連接之間沒(méi)有任何關(guān)系搁进。

HTTP是應(yīng)用層協(xié)議浪感,TCP是傳輸層協(xié)議。HTTP底層仍然采用TCP進(jìn)行傳輸數(shù)據(jù)拷获。TCP為HTTP提供了一層可靠的比特傳輸通道篮撑。HTTP一般交換的數(shù)據(jù)都不大,而每次連接都要進(jìn)行TCP三次握手匆瓜,很大一部分時(shí)間都消耗在這上面赢笨,有時(shí)候甚至能達(dá)到50%。如果能復(fù)用連接驮吱,就可以減少由于TCP三次握手所帶來(lái)的時(shí)延茧妒。

HTTP 1.1默認(rèn)開(kāi)啟keep-alive機(jī)制,從上面抓到的包也可以看到左冬。這樣桐筏,數(shù)據(jù)傳輸完成之后保持TCP連接不斷開(kāi),之后同域名下復(fù)用連接拇砰,繼續(xù)用這個(gè)通道傳輸數(shù)據(jù)梅忌。服務(wù)器在響應(yīng)一個(gè)請(qǐng)求后,可以保持這個(gè)連接keep-alive timeout的時(shí)間除破,在這個(gè)時(shí)間內(nèi)沒(méi)有請(qǐng)求牧氮,則關(guān)閉此連接;否則瑰枫,重新開(kāi)始倒計(jì)時(shí)keep-alive timeout時(shí)間踱葛。

http keep alive

HTTP有keep-alive機(jī)制,目的是可以在一個(gè)TCP
連接上傳輸多個(gè)HTTP事務(wù),以此提高通信效率尸诽。底層的TCP其實(shí)也有keep-alive機(jī)制甥材,它是為了探測(cè)TCP連接的活躍性。TCP層的keepalive可以在任何一方設(shè)置性含,可以是一端設(shè)置洲赵、兩端同時(shí)設(shè)置或者兩端都沒(méi)有設(shè)置。新建socket的時(shí)候需要設(shè)置胶滋,從而使得協(xié)議棧調(diào)用相關(guān)函數(shù)tcp_set_keepalive板鬓,來(lái)激活連接的keep-alive屬性悲敷。

當(dāng)網(wǎng)絡(luò)兩端建立了TCP連接之后究恤,閑置(雙方?jīng)]有任何數(shù)據(jù)流發(fā)送往來(lái))時(shí)間超過(guò)tcp_keepalive_time后,服務(wù)器內(nèi)核就會(huì)嘗試向客戶端發(fā)送偵測(cè)包后德,來(lái)判斷TCP連接狀況(有可能客戶端崩潰部宿、強(qiáng)制關(guān)閉了應(yīng)用、主機(jī)不可達(dá)等等)瓢湃。如果沒(méi)有收到對(duì)方的回答(ack包)理张,則會(huì)在 tcp_keepalive_intvl后再次嘗試發(fā)送偵測(cè)包,直到收到對(duì)方的ack,如果一直沒(méi)有收到對(duì)方的ack,一共會(huì)嘗試 tcp_keepalive_probes次绵患,每次的間隔時(shí)間在這里分別是15s, 30s, 45s, 60s, 75s雾叭。如果嘗試tcp_keepalive_probes次后,依然沒(méi)有收到對(duì)方的ack包,則會(huì)丟棄該TCP連接落蝙。TCP連接默認(rèn)閑置時(shí)間是2小時(shí)织狐,一般設(shè)置為30分鐘足夠了。

管道化連接

在keep-alive的基礎(chǔ)上筏勒,我們可以做地更進(jìn)一步移迫,在響應(yīng)到達(dá)之前,我們將多條請(qǐng)求按序放入請(qǐng)求隊(duì)列管行,服務(wù)端在收到請(qǐng)求后厨埋,必須按照順序?qū)?yīng)請(qǐng)求的響應(yīng)。但由于網(wǎng)絡(luò)環(huán)境非常復(fù)雜捐顷,因此即使請(qǐng)求是按順序發(fā)送的荡陷,也不一定是按順序到達(dá)服務(wù)端的。而且就算是服務(wù)端按序處理的迅涮,也不一定是按序返回給客戶端废赞,所以最好是在響應(yīng)中附帶一些可以標(biāo)識(shí)請(qǐng)求的參數(shù)。

為了安全起見(jiàn)逗柴,管道化的連接只適合“冪等”的請(qǐng)求蛹头,一般我們認(rèn)為:GET/HEAD/PUT/DELETE/TRACE/OPTIONS等方法都是冪等的。

小結(jié)

以上,就是所有HTTP的通信細(xì)節(jié)了渣蜗,足夠在日常開(kāi)發(fā) 作中使用了屠尊。更多沒(méi)有涉及的細(xì)節(jié)可以在用到的時(shí)候再去仔細(xì)研究。

文章看完了耕拷,不知道你對(duì)HTTP的理解有沒(méi)有更上一層樓讼昆?歡迎一起交流探討。

QR margin2

參考資料

【http長(zhǎng)連接】https://www.cnblogs.com/cswuyg/p/3653263.html

【http/tcp keep alive】https://segmentfault.com/a/1190000012894416

【http/tcp keep alive】https://laravel-china.org/articles/8020/on-the-keep-alive-and-tcp-keep-alive-in-the-http-protocol

【tcp keep alive】http://blog.51cto.com/zxtong/1788252

【http權(quán)威指南】https://book.douban.com/subject/10746113/

【HTTP狀態(tài)碼】https://www.cnblogs.com/starof/p/5035119.html

【HTTP協(xié)議】https://www.cnblogs.com/ranyonsue/p/5984001.html

【HTTP狀態(tài)分類】http://www.runoob.com/http/http-status-codes.html

【url編碼】http://www.ruanyifeng.com/blog/2010/02/url_encoding.html

【http/tcp keep alive】http://www.nowamagic.net/academy/detail/23350305

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骚烧,一起剝皮案震驚了整個(gè)濱河市浸赫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赃绊,老刑警劉巖既峡,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異碧查,居然都是意外死亡运敢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門忠售,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)传惠,“玉大人,你說(shuō)我怎么就攤上這事稻扬∝苑剑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵泰佳,是天一觀的道長(zhǎng)盼砍。 經(jīng)常有香客問(wèn)我,道長(zhǎng)乐纸,這世上最難降的妖魔是什么衬廷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮汽绢,結(jié)果婚禮上吗跋,老公的妹妹穿的比我還像新娘。我一直安慰自己宁昭,他們只是感情好跌宛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著积仗,像睡著了一般疆拘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寂曹,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天哎迄,我揣著相機(jī)與錄音回右,去河邊找鬼。 笑死漱挚,一個(gè)胖子當(dāng)著我的面吹牛翔烁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播旨涝,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蹬屹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了白华?” 一聲冷哼從身側(cè)響起慨默,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弧腥,沒(méi)想到半個(gè)月后厦取,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸟赫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年蒜胖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抛蚤。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖寻狂,靈堂內(nèi)的尸體忽然破棺而出岁经,到底是詐尸還是另有隱情,我是刑警寧澤蛇券,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布缀壤,位于F島的核電站,受9級(jí)特大地震影響纠亚,放射性物質(zhì)發(fā)生泄漏塘慕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一蒂胞、第九天 我趴在偏房一處隱蔽的房頂上張望图呢。 院中可真熱鬧,春花似錦骗随、人聲如沸蛤织。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)指蚜。三九已至,卻和暖如春涨椒,著一層夾襖步出監(jiān)牢的瞬間摊鸡,已是汗流浹背绽媒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留免猾,地道東北人些椒。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像掸刊,于是被迫代替她去往敵國(guó)和親免糕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1.TCP報(bào)頭格式 UDP報(bào)頭格式 TCP報(bào)頭格式 UDP報(bào)頭格式 具體的各部分解釋看 TCP報(bào)文格式詳解 - ...
    杰倫哎呦哎呦閱讀 2,444評(píng)論 0 5
  • 第一章忧侧、HTTP概述1石窑、Web瀏覽器、服務(wù)器和相關(guān)的Web應(yīng)用程序都是通過(guò)HTTP相互通信的蚓炬,HTTP是現(xiàn)代全球因...
    橫沖直撞666閱讀 634評(píng)論 0 1
  • 前言 本系列主要分析OKHttp源代碼的框架和設(shè)計(jì)思想松逊,因?yàn)镺KHttp實(shí)現(xiàn)了HTTP協(xié)議,所以在做源代碼分析之前...
    嘎啦果安卓獸閱讀 4,057評(píng)論 1 15
  • 今天我和兒子又一次來(lái)到了百花公園肯夏。沒(méi)有風(fēng)经宏,但是溫度特別低。太陽(yáng)暖洋洋的照在身上驯击。很多樹(shù)上的葉子已經(jīng)落光啦烁兰。大樹(shù)的樹(shù)...
    kenny515閱讀 97評(píng)論 0 1