一、Http協(xié)議

HTTP 的特性

  • HTTP 協(xié)議構建于 TCP/IP 協(xié)議之上裆馒,是一個應用層協(xié)議姊氓,默認端口號是 80
  • HTTP 是無連接無狀態(tài)的

HTTP 報文

請求報文

HTTP 協(xié)議是以 ASCII 碼傳輸,建立在 TCP/IP 協(xié)議之上的應用層規(guī)范喷好。規(guī)范把 HTTP 請求分為三個部分:狀態(tài)行他膳、請求頭、消息主體绒窑。類似于下面這樣:

<method> <request-URL> <version>
<headers>

<entity-body>

HTTP 定義了與服務器交互的不同方法棕孙,最基本的方法有4種,分別是GET些膨,POST蟀俊,PUT,DELETE订雾。URL全稱是資源描述符肢预,我們可以這樣認為:一個URL地址,它用于描述一個網(wǎng)絡上的資源洼哎,而 HTTP 中的GET烫映,POST,PUT噩峦,DELETE就對應著對這個資源的查锭沟,增,改识补,刪4個操作族淮。

GET 用于信息獲取,而且應該是安全的 和 冪等的凭涂。

所謂安全的意味著該操作用于獲取信息而非修改信息祝辣。換句話說,GET 請求一般不應產(chǎn)生副作用切油。就是說蝙斜,它僅僅是獲取資源信息,就像數(shù)據(jù)庫查詢一樣澎胡,不會修改孕荠,增加數(shù)據(jù)绢片,不會影響資源的狀態(tài)。

冪等的意味著對同一 URL 的多個請求應該返回同樣的結果岛琼。

GET 請求報文示例:
 GET /books/?sex=man&name=Professional HTTP/1.1
 Host: www.example.com
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
 Gecko/20050225 Firefox/1.0.1
 Connection: Keep-Alive
POST 表示可能修改變服務器上的資源的請求底循。
 POST / HTTP/1.1
 Host: www.example.com
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
 Gecko/20050225 Firefox/1.0.1
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 40
 Connection: Keep-Alive

 sex=man&name=Professional  

注意:GET 可提交的數(shù)據(jù)量受到URL長度的限制,HTTP 協(xié)議規(guī)范沒有對 URL 長度進行限制槐瑞。這個限制是特定的瀏覽器及服務器對它的限制理論上講熙涤,POST 是沒有大小限制的,HTTP 協(xié)議規(guī)范也沒有進行大小限制困檩,出于安全考慮祠挫,服務器軟件在實現(xiàn)時會做一定限制參考上面的報文示例,可以發(fā)現(xiàn) GET 和 POST 數(shù)據(jù)內(nèi)容是一模一樣的悼沿,只是位置不同等舔,一個在 URL 里,一個在 HTTP 包的包體里糟趾。

POST 提交數(shù)據(jù)的方式

HTTP 協(xié)議中規(guī)定 POST 提交的數(shù)據(jù)必須在 body 部分中慌植,但是協(xié)議中沒有規(guī)定數(shù)據(jù)使用哪種編碼方式或者數(shù)據(jù)格式。實際上义郑,開發(fā)者完全可以自己決定消息主體的格式蝶柿,只要最后發(fā)送的 HTTP 請求滿足上面的格式就可以。

但是非驮,數(shù)據(jù)發(fā)送出去特石,還要服務端解析成功才有意義歧沪。一般服務端語言如 PHP、Python 等蹂空,以及它們的 framework裂问,都內(nèi)置了自動解析常見數(shù)據(jù)格式的功能溶握。服務端通常是根據(jù)請求頭(headers)中的 Content-Type 字段來獲知請求中的消息主體是用何種方式編碼脊凰,再對主體進行解析燕垃。所以說到 POST 提交數(shù)據(jù)方案,包含了 Content-Type 和消息主體編碼方式兩部分栋盹。下面就正式開始介紹它們:

  • application/x-www-form-urlencoded
    這是最常見的 POST 數(shù)據(jù)提交方式施逾。瀏覽器的原生 <form> 表單敷矫,如果不設置 enctype 屬性例获,那么最終就會以 application/x-www-form-urlencoded 方式提交數(shù)據(jù)。上個小節(jié)當中的例子便是使用了這種提交方式曹仗≌ヌ溃可以看到 body 當中的內(nèi)容和 GET 請求是完全相同的。

  • multipart/form-data
    這又是一個常見的 POST 數(shù)據(jù)提交的方式怎茫。我們使用表單上傳文件時收壕,必須讓 <form> 表單的 enctype 等于 multipart/form-data妓灌。直接來看一個請求示例:

POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"

title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

這個例子稍微復雜點。首先生成了一個 boundary 用于分割不同的字段蜜宪,為了避免與正文內(nèi)容重復虫埂,boundary 很長很復雜。然后 Content-Type 里指明了數(shù)據(jù)是以 multipart/form-data 來編碼圃验,本次請求的 boundary 是什么內(nèi)容掉伏。消息主體里按照字段個數(shù)又分為多個結構類似的部分,每部分都是以 --boundary 開始澳窑,緊接著是內(nèi)容描述信息斧散,然后是回車,最后是字段具體內(nèi)容(文本或二進制)摊聋。如果傳輸?shù)氖俏募瑁€要包含文件名和文件類型信息。消息主體最后以 --boundary-- 標示結束麻裁。關于 multipart/form-data 的詳細定義箍镜,請前往 RFC1867 查看(或者相對友好一點的 MDN 文檔)。

這種方式一般用來上傳文件煎源,各大服務端語言對它也有著良好的支持鹿寨。

上面提到的這兩種 POST 數(shù)據(jù)的方式,都是瀏覽器原生支持的薪夕,而且現(xiàn)階段標準中原生 <form> 表單也只支持這兩種方式(通過 <form> 元素的 enctype 屬性指定脚草,默認為 application/x-www-form-urlencoded。其實 enctype 還支持 text/plain原献,不過用得非常少)馏慨。

隨著越來越多的 Web 站點,尤其是 WebApp姑隅,全部使用 Ajax 進行數(shù)據(jù)交互之后写隶,我們完全可以定義新的數(shù)據(jù)提交方式,例如 application/json讲仰,text/xml慕趴,乃至 application/x-protobuf 這種二進制格式,只要服務器可以根據(jù) Content-TypeContent-Encoding 正確地解析出請求鄙陡,都是沒有問題的冕房。

響應報文

HTTP 響應與 HTTP 請求相似,HTTP響應也由3個部分構成趁矾,分別是:

  • 狀態(tài)行
  • 響應頭(Response Header)
  • 響應正文

狀態(tài)行由協(xié)議版本耙册、數(shù)字形式的狀態(tài)代碼、及相應的狀態(tài)描述毫捣,各元素之間以空格分隔详拙。

常見的狀態(tài)碼有如下幾種:

  • 200 OK 客戶端請求成功
  • 301 Moved Permanently 請求永久重定向
  • 302 Moved Temporarily 請求臨時重定向
  • 304 Not Modified 文件未修改帝际,可以直接使用緩存的文件。
  • 400 Bad Request 由于客戶端請求有語法錯誤饶辙,不能被服務器所理解蹲诀。
  • 401 Unauthorized 請求未經(jīng)授權。這個狀態(tài)代碼必須和WWW-Authenticate報頭域一起使用
  • 403 Forbidden 服務器收到請求弃揽,但是拒絕提供服務侧甫。服務器通常會在響應正文中給出不提供服務的原因
  • 404 Not Found 請求的資源不存在,例如蹋宦,輸入了錯誤的URL
  • 500 Internal Server Error 服務器發(fā)生不可預期的錯誤披粟,導致無法完成客戶端的請求。
  • 503 Service Unavailable 服務器當前不能夠處理客戶端的請求冷冗,在一段時間之后守屉,服務器可能會恢復正常。
    下面是一個HTTP響應的例子:
HTTP/1.1 200 OK

Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:23:42 GMT
Content-Length:112

<html>...

持久連接

我們知道 HTTP 協(xié)議采用“請求-應答”模式蒿辙,當使用普通模式拇泛,即非 Keep-Alive 模式時,每個請求/應答客戶和服務器都要新建一個連接思灌,完成之后立即斷開連接(HTTP 協(xié)議為無連接的協(xié)議)俺叭;當使用 Keep-Alive 模式(又稱持久連接、連接重用)時泰偿,Keep-Alive 功能使客戶端到服務器端的連接持續(xù)有效熄守,當出現(xiàn)對服務器的后繼請求時,Keep-Alive 功能避免了建立或者重新建立連接耗跛。

在 HTTP 1.0 版本中裕照,并沒有官方的標準來規(guī)定 Keep-Alive 如何工作,因此實際上它是被附加到 HTTP 1.0協(xié)議上调塌,如果客戶端瀏覽器支持 Keep-Alive 晋南,那么就在HTTP請求頭中添加一個字段 Connection: Keep-Alive,當服務器收到附帶有 Connection: Keep-Alive 的請求時羔砾,它也會在響應頭中添加一個同樣的字段來使用 Keep-Alive 负间。這樣一來,客戶端和服務器之間的HTTP連接就會被保持姜凄,不會斷開(超過 Keep-Alive 規(guī)定的時間政溃,意外斷電等情況除外),當客戶端發(fā)送另外一個請求時檀葛,就使用這條已經(jīng)建立的連接玩祟。

在 HTTP 1.1 版本中,默認情況下所有連接都被保持屿聋,如果加入 "Connection: close" 才關閉空扎。目前大部分瀏覽器都使用 HTTP 1.1 協(xié)議,也就是說默認都會發(fā)起 Keep-Alive 的連接請求了润讥,所以是否能完成一個完整的 Keep-Alive 連接就看服務器設置情況转锈。

由于 HTTP 1.0 沒有官方的 Keep-Alive 規(guī)范,并且也已經(jīng)基本被淘汰楚殿,以下討論均是針對 HTTP 1.1 標準中的 Keep-Alive 展開的撮慨。
注意:

  • HTTP Keep-Alive 簡單說就是保持當前的TCP連接,避免了重新建立連接脆粥。

  • HTTP 長連接不可能一直保持砌溺,例如 Keep-Alive: timeout=5, max=100,表示這個TCP通道可以保持5秒变隔,max=100规伐,表示這個長連接最多接收100次請求就斷開。

  • HTTP 是一個無狀態(tài)協(xié)議匣缘,這意味著每個請求都是獨立的猖闪,Keep-Alive 沒能改變這個結果。另外肌厨,Keep-Alive也不能保證客戶端和服務器之間的連接一定是活躍的培慌,在 HTTP1.1 版本中也如此。唯一能保證的就是當連接被關閉時你能得到一個通知柑爸,所以不應該讓程序依賴于 Keep-Alive 的保持連接特性吵护,否則會有意想不到的后果。

  • 使用長連接之后表鳍,客戶端何址、服務端怎么知道本次傳輸結束呢?兩部分:1. 判斷傳輸數(shù)據(jù)是否達到了Content-Length 指示的大薪琛用爪;2. 動態(tài)生成的文件沒有 Content-Length ,它是分塊傳輸(chunked)胁镐,這時候就要根據(jù) chunked 編碼來判斷,chunked 編碼的數(shù)據(jù)在最后有一個空 chunked 塊盯漂,表明本次傳輸數(shù)據(jù)結束,詳見這里帖渠。什么是 chunked 分塊傳輸呢?下面我們就來介紹一下竭宰。

Transfer-Encoding

Transfer-Encoding 是一個用來標示 HTTP 報文傳輸格式的頭部值空郊。盡管這個取值理論上可以有很多,但是當前的 HTTP 規(guī)范里實際上只定義了一種傳輸取值——chunked锁摔。

如果一個HTTP消息(請求消息或應答消息)的Transfer-Encoding消息頭的值為chunked,那么哼审,消息體由數(shù)量未定的塊組成谐腰,并以最后一個大小為0的塊為結束。

每一個非空的塊都以該塊包含數(shù)據(jù)的字節(jié)數(shù)(字節(jié)數(shù)以十六進制表示)開始涩盾,跟隨一個CRLF (回車及換行),然后是數(shù)據(jù)本身砸西,最后塊CRLF結束终畅。在一些實現(xiàn)中,塊大小和CRLF之間填充有白空格(0x20)离福。

最后一塊是單行,由塊大械(0)絮识,一些可選的填充白空格,以及CRLF次舌。最后一塊不再包含任何數(shù)據(jù)彼念,但是可以發(fā)送可選的尾部,包括消息頭字段逐沙。消息最后以CRLF結尾。

一個示例響應如下:

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1A
and this is the second one
0

注意:

  • chunked 和 multipart 兩個名詞在意義上有類似的地方棚赔,不過在 HTTP 協(xié)議當中這兩個概念則不是一個類別的。multipart 是一種 Content-Type丧肴,標示 HTTP 報文內(nèi)容的類型,而 chunked 是一種傳輸格式捆毫,標示報頭將以何種方式進行傳輸冲甘。
  • chunked 傳輸不能事先知道內(nèi)容的長度,只能靠最后的空 chunk 塊來判斷濒憋,因此對于下載請求來說陶夜,是沒有辦法實現(xiàn)進度的。在瀏覽器和下載工具中黔夭,偶爾我們也會看到有些文件是看不到下載進度的羽嫡,即采用 chunked 方式進行下載。
  • chunked 的優(yōu)勢在于婚惫,服務器端可以邊生成內(nèi)容邊發(fā)送魂爪,無需事先生成全部的內(nèi)容。HTTP/2 不支持 Transfer-Encoding: chunked滓侍,因為 HTTP/2 有自己的 streaming 傳輸方式(Source:MDN - Transfer-Encoding)撩笆。

HTTP Pipelining(HTTP 管線化)

默認情況下 HTTP 協(xié)議中每個傳輸層連接只能承載一個 HTTP 請求和響應,瀏覽器會在收到上一個請求的響應之后浇衬,再發(fā)送下一個請求耘擂。在使用持久連接的情況下,某個連接上消息的傳遞類似于請求1 -> 響應1 -> 請求2 -> 響應2 -> 請求3 -> 響應3

HTTP Pipelining(管線化)是將多個 HTTP 請求整批提交的技術篙悯,在傳送過程中不需等待服務端的回應铃绒。使用 HTTP Pipelining 技術之后,某個連接上的消息變成了類似這樣請求1 -> 請求2 -> 請求3 -> 響應1 -> 響應2 -> 響應3矮燎。

注意下面幾點:

  • 管線化機制通過持久連接(persistent connection)完成赔癌,僅 HTTP/1.1 支持此技術(HTTP/1.0不支持)
  • 只有 GET 和 HEAD 請求可以進行管線化,而 POST 則有所限制
  • 初次創(chuàng)建連接時不應啟動管線機制峡谊,因為對方(服務器)不一定支持 HTTP/1.1 版本的協(xié)議
  • 管線化不會影響響應到來的順序刊苍,如上面的例子所示,響應返回的順序并未改變
  • HTTP /1.1 要求服務器端支持管線化啥纸,但并不要求服務器端也對響應進行管線化處理埠忘,只是要求對于管線化的請求不失敗即可
  • 由于上面提到的服務器端問題,開啟管線化很可能并不會帶來大幅度的性能提升名船,而且很多服務器端和代理程序對管線化的支持并不好旨怠,因此現(xiàn)代瀏覽器如 Chrome 和 Firefox 默認并未開啟管線化支持

更多關于 HTTP Pipelining 的知識可以參考這里

會話跟蹤

什么是會話迷扇?

客戶端打開與服務器的連接發(fā)出請求到服務器響應客戶端請求的全過程稱之為會話爽哎。

什么是會話跟蹤?

會話跟蹤指的是對同一個用戶對服務器的連續(xù)的請求和接受響應的監(jiān)視课锌。

為什么需要會話跟蹤?

瀏覽器與服務器之間的通信是通過HTTP協(xié)議進行通信的雏胃,而HTTP協(xié)議是”無狀態(tài)”的協(xié)議,它不能保存客戶的信息方仿,即一次響應完成之后連接就斷開了统翩,下一次的請求需要重新連接,這樣就需要判斷是否是同一個用戶鳍征,所以才有會話跟蹤技術來實現(xiàn)這種要求面徽。

會話跟蹤常用的方法:

(1)URL 重寫

URL(統(tǒng)一資源定位符)是Web上特定頁面的地址匣掸,URL重寫的技術就是在URL結尾添加一個附加數(shù)據(jù)以標識該會話,把會話ID通過URL的信息傳遞過去,以便在服務器端進行識別不同的用戶霎匈。

(2)隱藏表單域

將會話ID添加到HTML表單元素中提交到服務器送爸,此表單元素并不在客戶端顯示

(3)Cookie

Cookie 是Web 服務器發(fā)送給客戶端的一小段信息,客戶端請求時可以讀取該信息發(fā)送到服務器端墨吓,進而進行用戶的識別纹磺。對于客戶端的每次請求,服務器都會將 Cookie 發(fā)送到客戶端,在客戶端可以進行保存,以便下次使用秘症。

客戶端可以采用兩種方式來保存這個 Cookie 對象式矫,一種方式是保存在客戶端內(nèi)存中,稱為臨時 Cookie聪廉,瀏覽器關閉后這個 Cookie 對象將消失。另外一種方式是保存在客戶機的磁盤上锄列,稱為永久 Cookie邻邮。以后客戶端只要訪問該網(wǎng)站,就會將這個 Cookie 再次發(fā)送到服務器上筒严,前提是這個 Cookie 在有效期內(nèi),這樣就實現(xiàn)了對客戶的跟蹤摹恨。

Cookie 是可以被客戶端禁用的娶视。

(4)Session:

每一個用戶都有一個不同的 session,各個用戶之間是不能共享的寝凌,是每個用戶所獨享的孝赫,在 session 中可以存放信息。

在服務器端會創(chuàng)建一個 session 對象伐债,產(chǎn)生一個 sessionID 來標識這個 session 對象致开,然后將這個 sessionID 放入到 Cookie 中發(fā)送到客戶端,下一次訪問時祖今,sessionID 會發(fā)送到服務器拣技,在服務器端進行識別不同的用戶。

Session 的實現(xiàn)依賴于 Cookie徐绑,如果 Cookie 被禁用莫辨,那么 session 也將失效毅访。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喻粹,一起剝皮案震驚了整個濱河市草巡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌查乒,老刑警劉巖郁竟,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棚亩,死亡現(xiàn)場離奇詭異,居然都是意外死亡蔑舞,警方通過查閱死者的電腦和手機攻询,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門州弟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拯杠,你說我怎么就攤上這事啃奴。” “怎么了依溯?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵瘟则,是天一觀的道長。 經(jīng)常有香客問我醋拧,道長淀弹,這世上最難降的妖魔是什么庆械? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任缭乘,我火速辦了婚禮,結果婚禮上薄啥,老公的妹妹穿的比我還像新娘逛尚。我一直安慰自己,他們只是感情好到逊,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布滤钱。 她就那樣靜靜地躺著,像睡著了一般铜靶。 火紅的嫁衣襯著肌膚如雪他炊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天蚕苇,我揣著相機與錄音涩笤,去河邊找鬼盒件。 笑死,一個胖子當著我的面吹牛锰茉,可吹牛的內(nèi)容都是我干的切心。 我是一名探鬼主播片吊,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼协屡,長吁一口氣:“原來是場噩夢啊……” “哼肤晓!你這毒婦竟也來了?” 一聲冷哼從身側響起补憾,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盈匾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后岩瘦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窿撬,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了宰啦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖漓柑,靈堂內(nèi)的尸體忽然破棺而出叨吮,到底是詐尸還是另有隱情,我是刑警寧澤锋玲,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布涵叮,位于F島的核電站伞插,受9級特大地震影響媚污,放射性物質發(fā)生泄漏廷雅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一商架、第九天 我趴在偏房一處隱蔽的房頂上張望芥玉。 院中可真熱鬧,春花似錦皇型、人聲如沸砸烦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颜说。三九已至,卻和暖如春喊积,著一層夾襖步出監(jiān)牢的瞬間玄妈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工绎签, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酝锅,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓爸舒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親愉老。 傳聞我的和親對象是個殘疾皇子剖效,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

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