http1.1科普
因?yàn)楣ぷ髋龅搅艘恍┮苫笏钥戳嘶鸷膆ttp文檔, 簡(jiǎn)單地看, 簡(jiǎn)單地總結(jié)了一下, 本文只介紹http1.1的概念, 不介紹具體讓人心煩的細(xì)節(jié)(配置和行為).
什么是http
概念
全稱(chēng)是超文本傳輸協(xié)議. 何為超文本? 超文本就是文本(文本不一定是超文本).
http的本體是文本. 并且http2之前的版本(包含現(xiàn)在正在用的1.1)都是人類(lèi)可讀的文本.
再說(shuō)一下什么是協(xié)議? 協(xié)議就是雙方約定一些東西, 使用的時(shí)候大家都遵照規(guī)則執(zhí)行.
我們來(lái)類(lèi)比html, 超文本標(biāo)記語(yǔ)言. 本身是文本(div, p, img). 放到瀏覽器里解析的時(shí)候就會(huì)被畫(huà)成一個(gè)塊, 一個(gè)圖片等. 那么http也是如此, 普通的人類(lèi)可讀的文本, 進(jìn)行了一系列約定, 協(xié)議雙方根據(jù)一些關(guān)鍵詞來(lái)執(zhí)行某些約定的行為, 便是http了.
環(huán)境
那么http到底是在哪里發(fā)生的, http的三個(gè)屬性:
- http是應(yīng)用層協(xié)議.
- http是基于客戶(hù)端/服務(wù)端模型.
- http是無(wú)狀態(tài)協(xié)議.
高中就學(xué)過(guò)了osi七層協(xié)議, http是最上層的協(xié)議, 下面是基于傳輸層的(不僅限于tcp/ip).
客戶(hù)端指瀏覽器, 服務(wù)端指服務(wù)器. 順序是瀏覽器的某些動(dòng)作(比如輸入url并敲回車(chē))觸發(fā)http請(qǐng)求, 服務(wù)器接到請(qǐng)求返回, 形成了一次完整的http請(qǐng)求. http請(qǐng)求每次都是獨(dú)立的, 所以是無(wú)狀態(tài)協(xié)議.
總結(jié)
http就是瀏覽器使用傳輸層協(xié)議向服務(wù)器發(fā)出一些文本, 這些文本帶有約定的東西, 服務(wù)器根據(jù)約定的規(guī)則來(lái)分析內(nèi)容并作出響應(yīng). 學(xué)習(xí)http就是學(xué)習(xí)這些約定.
http消息
就像html是div, p, img一樣, http長(zhǎng)啥樣, 平時(shí)使用瀏覽器的調(diào)試工具或是http抓包工具都能看到. (當(dāng)然都是進(jìn)行過(guò)可視化處理的).
http消息分為請(qǐng)求(request)消息和響應(yīng)(response)消息. 即瀏覽器發(fā)出請(qǐng)求的消息和服務(wù)器響應(yīng)的消息.
消息組成
request和response的消息組成是一樣的.
request和response的每個(gè)部分的消息內(nèi)容不同. 下面介紹每個(gè)部分的具體內(nèi)容.
request
body有兩種情況: 單個(gè)資源: 此時(shí)header要定義content-type和content-length. 多個(gè)資源: 在content-type里定義boundary, 然后在body中用boundary來(lái)分隔多個(gè)資源. 例子鏈接
response
總結(jié)
至此, http已經(jīng)介紹完了. 我來(lái)舉一個(gè)簡(jiǎn)單的http的例子.
我打開(kāi)了瀏覽器, 敲入yo-cwj.com. 瀏覽器發(fā)出了http request.
GET https://yo-cwj.com HTTP/1.1 Host: yo-cwj.com User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive這個(gè)簡(jiǎn)單的get請(qǐng)求沒(méi)有body, header都是瀏覽器默認(rèn)帶上的.
然后收到了回復(fù):
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2.0.61 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml<html>陳文俊的博客</html>200, ok 代表請(qǐng)求成功, 倒數(shù)第二行空行代表header和body的分隔, 具體返回內(nèi)容是<html>xxx</html>, 瀏覽器獲得結(jié)果就可以去渲染頁(yè)面啦, 完美.
是的, http就是這么簡(jiǎn)單, http的結(jié)構(gòu)就是start-line, header, body三部分. 而協(xié)議復(fù)雜的地方大部分就在header了. header有一萬(wàn)個(gè)字段, 每個(gè)字段能研究一年. (所以要搞懂http需要一萬(wàn)年). 那么下面的章節(jié)簡(jiǎn)述一下經(jīng)常接觸的協(xié)議規(guī)則.
Cookie
介紹
http是無(wú)狀態(tài)協(xié)議, 但網(wǎng)站的登錄狀態(tài)/購(gòu)物車(chē)等是有狀態(tài)的, 就要借助cookie來(lái)實(shí)現(xiàn). cookie是儲(chǔ)存在瀏覽器上的信息. 會(huì)在向服務(wù)器發(fā)起請(qǐng)求的時(shí)候帶著, 以代表瀏覽器當(dāng)前的狀態(tài).
cookie原先的作用除了登錄/購(gòu)物車(chē), 還有儲(chǔ)存用戶(hù)主題, 分析用戶(hù)行為等. 但瀏覽器的行為會(huì)將cookie都帶到http請(qǐng)求中, 所以現(xiàn)在推薦使用現(xiàn)代storage api來(lái)儲(chǔ)存部分信息.
實(shí)現(xiàn)
兩個(gè)關(guān)鍵點(diǎn): cookie傳輸是通過(guò)http的header, cookie的儲(chǔ)存的地方是瀏覽器.
response header可以設(shè)置cookie:
Set-Cookie: <cookie-name>=<cookie-value>然后瀏覽器收到set-cookie頭以后會(huì)儲(chǔ)存cookie, 在發(fā)送請(qǐng)求時(shí)把對(duì)應(yīng)的cookie帶在request header的Cookie中, 格式是: k=v; k2=v2:
Cookie: yummy_cookie=choco; tasty_cookie=strawberry那么瀏覽器中會(huì)有很多cookie, 因?yàn)槲覀兘?jīng)常同時(shí)瀏覽不同的網(wǎng)頁(yè). 瀏覽器進(jìn)行request的時(shí)候把所有cookie帶上是不對(duì)的, 那么會(huì)帶上哪些cookie呢, 就涉及到cookie的作用范圍.
作用范圍
控制cookie作用范圍的關(guān)鍵字是Domain和Path, 如果都沒(méi)設(shè)置默認(rèn)行為是只向當(dāng)前路由發(fā)送cookie, 我的理解是什么路由接到set-cookie的就只向這個(gè)路由發(fā)送.
domain和path的語(yǔ)法是Domain=mozilla.org, Path=/docs. domain被設(shè)置的時(shí)候會(huì)向domain的所有子domain發(fā)送, 所以希望發(fā)送范圍越小就要設(shè)置得越細(xì). path相同.
生命周期
cookie的生命周期是瀏覽器關(guān)閉, 也可以在response header里通過(guò)設(shè)置expire來(lái)改變cookie的過(guò)期時(shí)間.
xss與csrf
因?yàn)闉g覽器通過(guò)document.cookie可以獲取自己的cookie. 通過(guò)一些手段發(fā)出一些請(qǐng)求并帶上cookie就可以獲取cookie來(lái)做不好的事情. 這也是http的特點(diǎn): 無(wú)狀態(tài). 所以理論上一切請(qǐng)求都是可以模擬的. (只要獲取了關(guān)鍵信息, 任何人都可以在他的電腦上模擬你正在登陸某網(wǎng)上銀行甚至進(jìn)行操作).
這些操作有: 讓頁(yè)面執(zhí)行一段js, 讓頁(yè)面append一個(gè)img, src的target是惡意網(wǎng)站. 所以防止xss攻擊只要做到控制用戶(hù)可進(jìn)行的操作或轉(zhuǎn)移用戶(hù)輸入就可以了.
題外話, 因?yàn)閖s和css和html都是明文的, 所以安全必須通過(guò)加密手段來(lái)強(qiáng)化.
跨域請(qǐng)求
跨域好像是每隔一段時(shí)間都會(huì)被問(wèn)到的問(wèn)題, 先來(lái)定義一下什么是跨域請(qǐng)求.
定義
違反同源策略的請(qǐng)求就叫跨域. 同源策略一句話就能說(shuō)完: 協(xié)議, 主機(jī), 端口都相同的url是同源url. 強(qiáng)調(diào)是都相同, 即使http和https的區(qū)別也算跨域. 左邊的鏈接舉了一些例子, 一看就明白.
那么從一個(gè)頁(yè)面向一個(gè)非同源的target發(fā)起了http請(qǐng)求, 這個(gè)請(qǐng)求就是跨域請(qǐng)求了.
觸發(fā)對(duì)象
那么什么情況下會(huì)發(fā)起跨域請(qǐng)求呢? 我的印象里百分之90的情況是js代碼發(fā)起的, 也就是或經(jīng)過(guò)框架包裝的xmlhttprequest. 下面這些都會(huì)觸發(fā)http請(qǐng)求:
- js代碼發(fā)起的, xmlhttprequest, fetch. 因?yàn)閒etch存在兼容問(wèn)題, 基本所有的框架封裝都是通過(guò)前者的.
- web字體. 通過(guò)@font-face.
- webgl texture.
- canvas用drawImage畫(huà)的Image或者Video.
- css和script標(biāo)簽.
跨域請(qǐng)求需要做的事情
說(shuō)了半天什么情況是跨域, 那么為什么要討論跨域呢? 當(dāng)然是報(bào)錯(cuò)了才會(huì)討論了.
因?yàn)榘踩P(guān)系, http是默認(rèn)阻止跨域請(qǐng)求的, 想要順利地進(jìn)行跨域請(qǐng)求, 必須在瀏覽器和服務(wù)器都進(jìn)行一些header設(shè)置, 來(lái)確認(rèn)這次跨域請(qǐng)求是雙方都認(rèn)同的. 就像你要?jiǎng)h除社交工具的好友前會(huì)進(jìn)行提示: 你是否要?jiǎng)h除好友xxx.
跨域相關(guān)的request和response的header都在左邊的鏈接里了, 這里只提一個(gè)作為例子:
(開(kāi)始講故事)
我的博客(https://yo-cwj.com)需要加載一... 因?yàn)椴┛屯泄艿姆?wù)器對(duì)博客大小有限制, 所以我把圖片放在了另外一個(gè)圖庫(kù)(https://picture-cwj.com). (下文就用博客和圖庫(kù)來(lái)代表2個(gè)地址).
博客使用了img標(biāo)簽來(lái)請(qǐng)求了圖庫(kù)的圖片. 圖庫(kù)返回的圖片response header 帶有:
Access-Control-Allow-Origin: https://yo-cwj.com博客進(jìn)行請(qǐng)求的request header帶有:
Origin: https://yo-cwj.com圖庫(kù)的response header告訴所有過(guò)來(lái)的請(qǐng)求: 我只給yo-cwj.com跨域. 博客的request header帶著表明身份的Origin header. 這樣一次不被阻止的跨域就完成了.
(故事完)
故事講完了, 博客是存在的, picture-cwj.com是不存在的. 簡(jiǎn)單的2個(gè)header就讓瀏覽器放行了跨域請(qǐng)求. 別的header都在故事前貼出來(lái)的鏈接中.
preflight request
強(qiáng)行翻譯: 跨域準(zhǔn)備請(qǐng)求.
當(dāng)跨域請(qǐng)求滿(mǎn)足了某些條件以后, 瀏覽器在跨域請(qǐng)求前會(huì)發(fā)起一次preflight request, 用來(lái)確認(rèn)即將發(fā)送的請(qǐng)求是否被允許.
preflight請(qǐng)求的method是options, 之前說(shuō)的跨域相關(guān)的header大部分是和preflight相關(guān)的.
下面介紹發(fā)起preflight請(qǐng)求的觸發(fā)條件:
只要滿(mǎn)足任何一個(gè)條件就會(huì)發(fā)起preflight請(qǐng)求. 具體條件在左邊的鏈接中.
緩存
關(guān)于緩存暫時(shí)只做概念介紹, 緩存的控制也都是header控制的.
概念
什么是緩存? 當(dāng)同一個(gè)請(qǐng)求進(jìn)行了2次以上, 瀏覽器不真正向?yàn)g覽器發(fā)起請(qǐng)求而直接返回之前儲(chǔ)存的結(jié)果.
緩存哲學(xué)
緩存的好處是: 提高瀏覽器響應(yīng)速度, 節(jié)省服務(wù)器帶寬. 因?yàn)闆](méi)有與服務(wù)器真正數(shù)據(jù)交互, 也獲得了期望里的數(shù)據(jù).
緩存的問(wèn)題也非常明顯, 獲得的數(shù)據(jù)是緩存里的, 而不是最新的. 所以緩存的關(guān)鍵就在于猜測(cè)哪些數(shù)據(jù)是不經(jīng)常更新的. 猜測(cè)什么類(lèi)型的數(shù)據(jù)的更新頻率是多少, 并使用緩存相關(guān)的header來(lái)控制. 比如某門(mén)戶(hù)網(wǎng)站的首頁(yè)html是不經(jīng)常更新的, 或者是每小時(shí)一更新, 而首頁(yè)輪播的圖片是十分鐘更新的.
緩存類(lèi)型
緩存類(lèi)型分為本地緩存和共享緩存.
我們概念中的, 或者說(shuō)我們經(jīng)常使用的都是本地緩存.
共享緩存是指ISP對(duì)服務(wù)器的緩存, 之前聽(tīng)說(shuō)淘寶怎么能讓網(wǎng)速更快, 離用戶(hù)最近的地方是ISP機(jī)房, 所以把淘寶首頁(yè)放在ISP機(jī)房就行了.
新鮮度檢查
有一種緩存的機(jī)制是新鮮度檢查. 之前說(shuō)的緩存response是: 200 OK (from disk cache). 新鮮度檢查是根據(jù)cache-control: max-age=xxx向服務(wù)器發(fā)起新鮮度檢查. 如果返回結(jié)果是304(not modified), 服務(wù)器將不返回?cái)?shù)據(jù), 使用瀏覽器緩存的數(shù)據(jù), 從而節(jié)省數(shù)據(jù)下載時(shí)間和帶寬.
參考鏈接
- http header
- request methods
- response status
總結(jié)
- 上一篇: 05 商品模块
- 下一篇: [BZOJ] 3191 [JLOI201