http1.1科普
因為工作碰到了一些疑惑所以看了火狐的http文檔, 簡單地看, 簡單地總結了一下, 本文只介紹http1.1的概念, 不介紹具體讓人心煩的細節(配置和行為).
什么是http
概念
全稱是超文本傳輸協議. 何為超文本? 超文本就是文本(文本不一定是超文本).
http的本體是文本. 并且http2之前的版本(包含現在正在用的1.1)都是人類可讀的文本.
再說一下什么是協議? 協議就是雙方約定一些東西, 使用的時候大家都遵照規則執行.
我們來類比html, 超文本標記語言. 本身是文本(div, p, img). 放到瀏覽器里解析的時候就會被畫成一個塊, 一個圖片等. 那么http也是如此, 普通的人類可讀的文本, 進行了一系列約定, 協議雙方根據一些關鍵詞來執行某些約定的行為, 便是http了.
環境
那么http到底是在哪里發生的, http的三個屬性:
- http是應用層協議.
- http是基于客戶端/服務端模型.
- http是無狀態協議.
高中就學過了osi七層協議, http是最上層的協議, 下面是基于傳輸層的(不僅限于tcp/ip).
客戶端指瀏覽器, 服務端指服務器. 順序是瀏覽器的某些動作(比如輸入url并敲回車)觸發http請求, 服務器接到請求返回, 形成了一次完整的http請求. http請求每次都是獨立的, 所以是無狀態協議.
總結
http就是瀏覽器使用傳輸層協議向服務器發出一些文本, 這些文本帶有約定的東西, 服務器根據約定的規則來分析內容并作出響應. 學習http就是學習這些約定.
http消息
就像html是div, p, img一樣, http長啥樣, 平時使用瀏覽器的調試工具或是http抓包工具都能看到. (當然都是進行過可視化處理的).
http消息分為請求(request)消息和響應(response)消息. 即瀏覽器發出請求的消息和服務器響應的消息.
消息組成
request和response的消息組成是一樣的.
request和response的每個部分的消息內容不同. 下面介紹每個部分的具體內容.
request
body有兩種情況: 單個資源: 此時header要定義content-type和content-length. 多個資源: 在content-type里定義boundary, 然后在body中用boundary來分隔多個資源. 例子鏈接
response
總結
至此, http已經介紹完了. 我來舉一個簡單的http的例子.
我打開了瀏覽器, 敲入yo-cwj.com. 瀏覽器發出了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這個簡單的get請求沒有body, header都是瀏覽器默認帶上的.
然后收到了回復:
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 代表請求成功, 倒數第二行空行代表header和body的分隔, 具體返回內容是<html>xxx</html>, 瀏覽器獲得結果就可以去渲染頁面啦, 完美.
是的, http就是這么簡單, http的結構就是start-line, header, body三部分. 而協議復雜的地方大部分就在header了. header有一萬個字段, 每個字段能研究一年. (所以要搞懂http需要一萬年). 那么下面的章節簡述一下經常接觸的協議規則.
Cookie
介紹
http是無狀態協議, 但網站的登錄狀態/購物車等是有狀態的, 就要借助cookie來實現. cookie是儲存在瀏覽器上的信息. 會在向服務器發起請求的時候帶著, 以代表瀏覽器當前的狀態.
cookie原先的作用除了登錄/購物車, 還有儲存用戶主題, 分析用戶行為等. 但瀏覽器的行為會將cookie都帶到http請求中, 所以現在推薦使用現代storage api來儲存部分信息.
實現
兩個關鍵點: cookie傳輸是通過http的header, cookie的儲存的地方是瀏覽器.
response header可以設置cookie:
Set-Cookie: <cookie-name>=<cookie-value>然后瀏覽器收到set-cookie頭以后會儲存cookie, 在發送請求時把對應的cookie帶在request header的Cookie中, 格式是: k=v; k2=v2:
Cookie: yummy_cookie=choco; tasty_cookie=strawberry那么瀏覽器中會有很多cookie, 因為我們經常同時瀏覽不同的網頁. 瀏覽器進行request的時候把所有cookie帶上是不對的, 那么會帶上哪些cookie呢, 就涉及到cookie的作用范圍.
作用范圍
控制cookie作用范圍的關鍵字是Domain和Path, 如果都沒設置默認行為是只向當前路由發送cookie, 我的理解是什么路由接到set-cookie的就只向這個路由發送.
domain和path的語法是Domain=mozilla.org, Path=/docs. domain被設置的時候會向domain的所有子domain發送, 所以希望發送范圍越小就要設置得越細. path相同.
生命周期
cookie的生命周期是瀏覽器關閉, 也可以在response header里通過設置expire來改變cookie的過期時間.
xss與csrf
因為瀏覽器通過document.cookie可以獲取自己的cookie. 通過一些手段發出一些請求并帶上cookie就可以獲取cookie來做不好的事情. 這也是http的特點: 無狀態. 所以理論上一切請求都是可以模擬的. (只要獲取了關鍵信息, 任何人都可以在他的電腦上模擬你正在登陸某網上銀行甚至進行操作).
這些操作有: 讓頁面執行一段js, 讓頁面append一個img, src的target是惡意網站. 所以防止xss攻擊只要做到控制用戶可進行的操作或轉移用戶輸入就可以了.
題外話, 因為js和css和html都是明文的, 所以安全必須通過加密手段來強化.
跨域請求
跨域好像是每隔一段時間都會被問到的問題, 先來定義一下什么是跨域請求.
定義
違反同源策略的請求就叫跨域. 同源策略一句話就能說完: 協議, 主機, 端口都相同的url是同源url. 強調是都相同, 即使http和https的區別也算跨域. 左邊的鏈接舉了一些例子, 一看就明白.
那么從一個頁面向一個非同源的target發起了http請求, 這個請求就是跨域請求了.
觸發對象
那么什么情況下會發起跨域請求呢? 我的印象里百分之90的情況是js代碼發起的, 也就是或經過框架包裝的xmlhttprequest. 下面這些都會觸發http請求:
- js代碼發起的, xmlhttprequest, fetch. 因為fetch存在兼容問題, 基本所有的框架封裝都是通過前者的.
- web字體. 通過@font-face.
- webgl texture.
- canvas用drawImage畫的Image或者Video.
- css和script標簽.
跨域請求需要做的事情
說了半天什么情況是跨域, 那么為什么要討論跨域呢? 當然是報錯了才會討論了.
因為安全關系, http是默認阻止跨域請求的, 想要順利地進行跨域請求, 必須在瀏覽器和服務器都進行一些header設置, 來確認這次跨域請求是雙方都認同的. 就像你要刪除社交工具的好友前會進行提示: 你是否要刪除好友xxx.
跨域相關的request和response的header都在左邊的鏈接里了, 這里只提一個作為例子:
(開始講故事)
我的博客(https://yo-cwj.com)需要加載一... 因為博客托管的服務器對博客大小有限制, 所以我把圖片放在了另外一個圖庫(https://picture-cwj.com). (下文就用博客和圖庫來代表2個地址).
博客使用了img標簽來請求了圖庫的圖片. 圖庫返回的圖片response header 帶有:
Access-Control-Allow-Origin: https://yo-cwj.com博客進行請求的request header帶有:
Origin: https://yo-cwj.com圖庫的response header告訴所有過來的請求: 我只給yo-cwj.com跨域. 博客的request header帶著表明身份的Origin header. 這樣一次不被阻止的跨域就完成了.
(故事完)
故事講完了, 博客是存在的, picture-cwj.com是不存在的. 簡單的2個header就讓瀏覽器放行了跨域請求. 別的header都在故事前貼出來的鏈接中.
preflight request
強行翻譯: 跨域準備請求.
當跨域請求滿足了某些條件以后, 瀏覽器在跨域請求前會發起一次preflight request, 用來確認即將發送的請求是否被允許.
preflight請求的method是options, 之前說的跨域相關的header大部分是和preflight相關的.
下面介紹發起preflight請求的觸發條件:
只要滿足任何一個條件就會發起preflight請求. 具體條件在左邊的鏈接中.
緩存
關于緩存暫時只做概念介紹, 緩存的控制也都是header控制的.
概念
什么是緩存? 當同一個請求進行了2次以上, 瀏覽器不真正向瀏覽器發起請求而直接返回之前儲存的結果.
緩存哲學
緩存的好處是: 提高瀏覽器響應速度, 節省服務器帶寬. 因為沒有與服務器真正數據交互, 也獲得了期望里的數據.
緩存的問題也非常明顯, 獲得的數據是緩存里的, 而不是最新的. 所以緩存的關鍵就在于猜測哪些數據是不經常更新的. 猜測什么類型的數據的更新頻率是多少, 并使用緩存相關的header來控制. 比如某門戶網站的首頁html是不經常更新的, 或者是每小時一更新, 而首頁輪播的圖片是十分鐘更新的.
緩存類型
緩存類型分為本地緩存和共享緩存.
我們概念中的, 或者說我們經常使用的都是本地緩存.
共享緩存是指ISP對服務器的緩存, 之前聽說淘寶怎么能讓網速更快, 離用戶最近的地方是ISP機房, 所以把淘寶首頁放在ISP機房就行了.
新鮮度檢查
有一種緩存的機制是新鮮度檢查. 之前說的緩存response是: 200 OK (from disk cache). 新鮮度檢查是根據cache-control: max-age=xxx向服務器發起新鮮度檢查. 如果返回結果是304(not modified), 服務器將不返回數據, 使用瀏覽器緩存的數據, 從而節省數據下載時間和帶寬.
參考鏈接
- http header
- request methods
- response status
總結
- 上一篇: 05 商品模块
- 下一篇: 【Android Studio安装部署系