從 HTTP 瞎逼逼到 HTTP/2

我真的是在瞎逼逼,因為光是 HTTP,就足夠講一塊磚頭了。而且,HTTP 只是協議棧的應用層的其中一個協議:),不過其他協議都不在本文討論范圍之內。如有疏漏,請指正。

概述:HTTP vs HTTPS vs HTTP/2 vs SSL vs TLS:這些都是啥子跟啥子?

很多縮寫詞被用于描述客戶端與服務器端交流的過程。這些詞經常被不熟悉內部原理的人混淆。

HTTP (Hypertext Transfer Protocol) 是客戶端和服務器端都必須實現的基本交流協議。它涉及到請求 (requests),響應 (responses),會話 (sessions),緩存 (caching),認證 (* authentication) 以及更多。在這個協議以及 HTML (Hypertext Markup Language*) 上的工作,開始于 1989 年,由在 CERN 的 Sir Tim Berners-Lee 和他的團隊主持。這個協議的第一個官方版本 (HTTP 1.0) 發布于 1996 年,隨后在 1997 年發布了現在廣泛使用的版本 (HTTP 1.1)。

這個協議在瀏覽器和服務器間傳輸明文 (clear) 信息,允許通過傳輸信息的網絡查看傳輸的信息。這會產生安全的擔憂,所以 HTTP Secure (HTTPS) 被引入了。HTTPS 允許客戶端和服務器端先建立一個加密的通道,然后通過這個通道傳輸明文信息,有效地防止了信息的竊聽。

加密通道是通過 Transport Layer Security (TLS) 協議創建的,這個協議以前叫 Secure Socket Layer (SSL)。這兩個術語經常互換著使用。SSL 3.0 正在被 TLS 1.0 替代。SSL 是 Netscape 開發的協議,而 TLS 是一個 IETF 標準。在寫這篇文章的時候,所有版本的 SSL (1.0, 2.0, 3.0) 都由于許多的安全問題而被廢棄,使用它們將會在現代瀏覽器中產生警告,TLS 版本 (1.0, 1.1, 1.2) 正在使用中,1.3 版本現在還是草案。

所以,在大約 1996 或 1997 的某個時間,我們有了互聯網的當前穩定版本 (有或者沒有 SSL/TLS 的 HTTP 1.1),這個 HTTP 版本仍然驅動著現在絕大多數網站。以前,HTTP 用于非敏感通信,比如閱讀新聞,而 HTTPS 用于敏感通信,比如認證和電子商務。然而,對隱私權的關注不斷增加,一些瀏覽器如 Google Chrome 現在會標記 HTTP 網站 為 “not private”,將在未來針對 HTTP 引入警告。

HTTP 協議的下一代升級版 —— HTTP/2,于 2015 年發布,正在被越來越多的網站所采納。這個協議增加了新的特色,如 壓縮 (compression),多路復用 (multiplexing),請求優先級 (prioritization of requests)等,用于減少等待時間、提升性能和安全性。

在 HTTP 1.1 版本,安全連接是可選的,你可以使用 HTTP 或 HTTPS,但在 HTTP/2,安全連接幾乎是強制的,即使標準定義了有 TLS 的 HTTP/2 和沒有 TLS 的 HTTP/2,但大部分瀏覽器提供商已經聲明它們將只支持擁有 TLS 的 HTTP/2。

HTTP

HTTP 的基本性質

簡單

HTTP 的消息被設計為簡單可讀。這一點只要你打開瀏覽器控制臺看看請求和響應頭就知道了。

可擴展

除了規范規定的那些 header,我們會看到很多非官方規定的 header,這些擴展的 header 可以用來實現新的功能。

無狀態

這意味著即使你對服務器發起過一次請求,當你再發起一次請求時,服務器也不知道你拜訪過它,基本的 HTTP 請求中是不含狀態信息的。所幸我們可以增加 cookie 的頭部擴展來記錄狀態信息。

使用可靠連接

HTTP 依賴于運輸層的 TCP 協議進行消息傳遞,而 TCP 是可靠的。

狀態碼

狀態碼的第一個數字代表當前響應類型

  • 1xx - 信息,請求已被服務器接收,繼續處理
  • 2xx - 成功,請求已成功被服務器接收、理解、并接受
  • 3xx - 重定向,需要后續操作才能完成這一請求
  • 4xx - 客戶端錯誤,請求含有詞法錯誤或者無法被執行
  • 5xx - 服務器端錯誤,服務器在處理某個正確請求時發生錯誤

HTTP 的請求方法

較少用的方法

  • OPTIONS:請求服務器告知其支持的各種功能。可以詢問服務器通常支持哪些方法,或者對某些特殊資源支持哪些方法
  • HEAD:向服務器發出指定資源的請求,但服務器在響應中只返回首部,不會返回實體的主體即資源的 body 部分
  • PUT:向服務器寫入資源
  • DELETE:請服務器刪除請求 URL 所指定的資源
  • TRACE:HTTP 請求在傳輸的過程中是可能會被修改的。這個方法允許客戶端在最終將請求發送給服務器時,看看它變成了什么樣子。主要用于測試或診斷
  • CONNECT:這個方法將請求的連接轉換為透明的 TCP/IP 隧道,通常用于加快基于 SSL 加密的通信
  • PATCH:這個方法請求對資源進行局部修改

常用方法

GET && POST

GET 是最常用的方法,用于請求服務器發送某個資源。POST 方法用于向服務器發送數據,注意這和 PUT 的寫入資源是不同的,寫入的資源是存儲在服務器的,而發送的數據會發送到其他地方去處理,這可能會導致新資源的創建或已存在資源的更新,POST 通常用于支持 HTML 表單。

這兩個方法有什么區別?

冪等
在數學中,冪等有兩種主要含義:

  • 在某二元運算下,冪等元素是指被自己重復運算的結果等于它自己的元素。例如 0 * 0 仍然為 0,所以 0 在乘法下是冪等的。
  • 某一元運算為冪等的時,其作用在任一元素兩次后會和其作用一次的結果相同,例如 恒等函數 f(x) = x 就是冪等的。

在計算機網絡中,假如在不考慮諸如錯誤或者過期等問題的情況下,若干次請求的副作用與單次請求相同或者根本沒有副作用,那么這些請求方法就能夠被視作是“冪等”的。

我們知道,GET 用于表單數據提交時,表單數據會被編碼在請求的 URI 上,這樣極不安全,因為請求的地址可能在情趣到達目的地之前被打印,然后被第三方看到。而 POST 提交的數據是放在請求體中的,比 GET 提交數據安全,當然,沒有 HTTPS,POST 提交的數據也能被看到。

但是最主要的區別,應該為如下三點:

  • 安全性(safe): GET 請求是安全的,這里的安全是指 GET 方法只獲取信息而不做其他操作。而 POST 請求則是不安全的,因為它會更新或創建資源。

  • 冪等性(idempotent): GET 請求是冪等的,冪等就是上面所說的若干次請求的副作用與單次請求相同,而 POST 請求則是不冪等的。

  • 可緩存性(cacheable): GET 請求的響應是可緩存的,POST 請求的響應一般是不可緩存的,除非設置了合適的 Cache-Control 或 Expires 頭部字段。

HTTPS

為什么優先要使用 HTTPS?

有三個主要原因:

  • 機密性 (Confidentiality)

這能保護通信的雙方在公共媒介中免遭信息竊聽。如果沒有 HTTPS,當你通過 WiFi 接入點網上購物時,WiFi 接入點的運營者就能看到你的信用卡之類的隱私信息。

  • 數據完整性 (Integrity)

這能保證信息能不受改變地完整到達目的地。比如,WiFi 可以在我們的網站上增加廣告,降低圖片質量或者改變文章的內容。HTTPS 能確保網站不被更改。

  • 身份驗證 (Authentication)

這能保證網站不會是假冒的,域名是哪個,站點就是哪個。比如,一些運行 WiFi 接入點的猥瑣之人可以把瀏覽器導向一些假冒的網站。HTTPS 能確保example.com就是真的example.com,有些安全證書甚至要檢查網站的合法身份,讓你知道yourbank.comYourBank, Inc,即 YourBank 公司。

使用 HTTP 頭部字段保護你的 web 應用

禁用秘密信息的緩存

瀏覽器默認緩存 HTTP 的 GET 請求的響應,如果使用的是共享個人電腦 (網吧不就是么?),那么猥瑣之人就能通過訪問瀏覽器的緩存得到他人的隱私信息。所以我們要在返回隱私信息時使用三個響應頭字段來禁用客戶端的緩存:

  • Cache-Control: no-cache, no-store, max-age=0, must-revalidate
    cache-control 字段用來指定在這次的請求/響應鏈中的所有緩存機制都必須遵守的指令。上面的三個指令告訴客戶端和代理在使用緩存前必須送請求到服務器進行驗證,不要儲存響應,在請求發生之后的 0 秒后緩存即過期,在使用緩存的響應前檢查其狀態并禁止使用過期的響應。

  • Pragma: no-cache
    這個字段用于向后兼容 HTTP 1.0,確保老客戶端能不緩存響應。

  • Expires: -1
    這個字段用于指定響應過期的時間戳。指定為-1的話,客戶端就會立即把響應當做過期的,這就避免了緩存。

請在需要保護隱私時才禁用緩存,否則你的應用加載速度將大打折扣。

強制 HTTPS

HTTPS 的重要性我在前面已經說了,要強制 HTTPS,我們要使用 HTTP Strict Transport Security (HSTS) 頭部字段,具體可以設置為Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

max-age是指示瀏覽器為當前域名緩存這個頭部字段指定秒數,這里是緩存一年。includeSubDomains指示瀏覽器將 HSTS 應用于當前域名的所有子域名。preload強制瀏覽器總是安全地加載你的 web 應用,甚至在你第一次訪問網站且未收到響應前,這個特性是通過將一個安全預加載的域名的列表硬編碼到瀏覽器代碼中實現的,要使用這個特性你需要在 HSTS Preload List Submission 注冊你的域名,當然啦,使用這個指令你得確保你的應用能只使用 HTTPS。

允許 XSS 過濾

XSS 即跨站腳本攻擊,是很普遍也很簡單的網絡攻擊手法。我們會使用X-XSS-Protection: 1; mode=blockX-XSS-Protection這個字段指示瀏覽器是否為當前頁面開啟瀏覽器內建的 XSS 過濾機制并覆蓋瀏覽器本身的相關設置。1表示允許過濾器,反之為0mode=block指示瀏覽器在檢測到 XSS 攻擊后禁止加載整個頁面。

控制 Framing

一個 iframe 是一個可以允許在一個父 web 應用中嵌套一個 web 應用的 DOM 元素。這個元素可以讓點擊劫持 (* clickjacking) 更容易。點擊劫持可以欺騙用戶點擊非用戶本意的東西。為了阻止這種攻擊,我們使用X-Frame-Options: SAMEORIGINX-Frame-Options*這個字段指示瀏覽器是否允許你的 web 應用嵌套在另一個 web 應用中,SAMEORIGIN 表示你的應用可以在同域名頁面的 frame 中展示。注意當在 Content-Security-Policy 字段中指定了 frame-ancestors 時,則 X-Frame-Options 被忽略,見 這里

明確白名單

CSP (Content Security Policy) 定義了一個非常強大的基于瀏覽器的安全機制,允許對你的 web 應用中的資源加載和腳本執行加以控制。有了它,你可以將允許腳本加載、ajax 調用、圖片和樣式表加載的域列入白名單,可以允許或禁止內聯腳本和動態腳本等。我們可以通過簡單設置Content-Security-Policy: script-src 'self'來允許同源的腳本加載以及阻止動態腳本和內聯腳本執行。Content-Security-Policy 是個比較復雜的頭部字段,詳細的配置可以在這里看到。

阻止 Content-Type 嗅探

為了使用戶體驗更連貫,很多瀏覽器實現了一個叫 “Content-Type 嗅探” 或 “MIME 嗅探” 的功能,這個功能使瀏覽器能通過實際資源的比特位檢測 HTTP 中響應資源的類型而不理會響應頭中的Content-Type字段聲明的資源類型。但這會導致 MIME 混淆攻擊 (MIME confusion attack)。于是乎,我們要使用X-Content-Type-Options: nosniff,指示瀏覽器在處理獲取的資源時不要使用嗅探。

HTTP/2

多數主流瀏覽器已經在2015年底支持了該協議。此外,根據 W3Techs 的數據,在2017年5月,在排名前一千萬的網站中,有13.7% 支持了HTTP/2。這真真是極吼滴!有圖有真相。

http2 support

HTTP/2 相比 HTTP 1.x 的主要區別

是二進制的而非文本的

有別于 HTTP/1.1 中的明文請求,HTTP/2 將一個 TCP 連接分為若干個流 (stream),每個流中可以傳輸若干消息 (message),每個消息由若干最小的二進制幀 (frame) 組成。這樣更利于高效地解析,而且不容易出錯,畢竟 HTTP/1.x 的 header 中有空白行、大小寫、換行、空行之類的規定。

是完全多路復用而非按順序和阻塞的

HTTP/1.x 有一個 head-of-line blocking 的問題,它會讓一個連接一次只能發送一個請求。多路復用允許多個請求和響應消息同時發出,甚至可以混合一個消息的一部分和另一個消息。

只開一個連接用于并發的請求

HTTP/1.x 中為了加載資源會同時打開多個 TCP 連接,每個連接在響應時又都會發送大量數據,存在中間網絡 (intervening network) 緩沖區溢出的危險,導致網絡阻塞和重發 (* retransmits*)。而且,使用那么多的 TCP 連接也是一種大量占用網絡資源的行為。

壓縮頭部

在大型網站中,一個頁面往往要請求大量資源并得到相應,算上那些往返的話,那么頭部就會占據相當大的開銷,所以壓縮頭部的好處便變得顯而易見了。

允許服務器主動推送資源給客戶端

在 HTTP/1.x 中,當瀏覽器請求了一個頁面,服務器發送了 HTML 頁面的響應,然后服務器需要等待瀏覽器解析了 HTML 文件后再發起嵌入在 HTML 頁面中的多個資源的請求,想想都覺得慢。而服務器端推送避免了這種往返的延遲,服務器會主動推送它認為的客戶端會需要緩存的資源。要小心的是,這個功能濫用的話,會損害性能。

如何擁抱 HTTP/2?

HTTP/2 是向后兼容 HTTP/1.1 的,所以完全不需要擔心現有的網站會發生什么問題。然而,很多對于 HTTP/1.1 來說是最佳實踐的技巧卻會在使用 HTTP/2 時降低性能。再者,從 HTTP/1.1 轉向 HTTP/2 勢必是漫長的,因為服務器端升級容易,但只要一日絕大多數人仍然使用著老舊甚至是史前瀏覽器,客戶端就會是扎心窩的痛。我們需要做些過渡時期的事。

轉向 TLS

第一要務是讓你的網站運行在安全連接上,因為廠商大佬們已經說過了:我們哥們幾個只支持有 TLS 的 HTTP/2,那些不支持 TLS 的可以歇菜了。所以國內大片的 HTTP 網站們要好好考慮轉向 HTTPS 的事了。

雪碧圖不再總是最佳的選擇

在 HTTP/1.1 中,對于瀏覽器來說,獲取一個巨大的圖片文件比請求多個小圖片文件高效,這是因為多個請求會互相排隊,增加加載時間。通常的做法是把多個小圖片轉成一個雪碧圖。

轉成一個雪碧圖就只需要一個 HTTP 請求了。但是咧,如果一個頁面中只使用到雪碧圖中的一個圖標,仍然下載整個雪碧圖就顯得不是很好了。HTTP/2 擁有多路復用的能力,所以多個請求排隊的事已經不存在了,很多時候單個地請求圖片將是更好的選擇。當然,需要使用所有圖標時,雪碧圖仍然是需要的。

使用 Data URI 內嵌圖片是一種阻礙

在 HTTP/1.1 中,為了減少 HTTP 請求,你可以把圖片直接以 Data URI 的形式嵌入 CSS 或 HTML 文件中。因為轉成的字符編碼會很長,自然增加了 CSS 或 HTML 文件的大小。在 HTTP/2 中,HTTP 請求變得廉價,這種 “最佳實踐” 便變成了一種妨礙。

合并 CSS 文件和 JavaScript 文件未必好

我們在應用的構建階段,通常會合并那些小的 CSS 和 JavaScript 文件,本意是減少 HTTP 請求。但是在 HTTP/2 中,HTTP 請求是廉價的,合并便不再顯得有優勢。可能更糟糕的是,如果你因為合并引入了很多非本頁面所需的文件,反而拖慢了加載速度,當然,你是可以通過 webpack 來配置相應頁面所需的相應文件的,可是別忘了,合并文件是要引入大量處理合并的代碼的,在 HTTP/2 廉價的請求中,這些多余的處理代碼看來有點多余,止增笑耳。

域名分片可能會坑你

在 HTTP/1.1 中,每個域名能打開的連接是受到限制的,大概為 6 - 8 個,具體取決于瀏覽器實現。如果你實在要加載大量資源,其中一個方法就是從多個域名中獲取資源,這就是域名分片 (domain sharding)。這個方法能實現更好的加載時間,也有能導致問題,當然,準備這種服務就會有額外的開支。HTTP/2 則移除了域名分片的需求,在 HTTP/2 下,瀏覽器只為每個域名打開一個連接,但是人家有多路復用嘛,并發請求的數量根本不受限制 (當然也可以通過 SETTINGS_MAX_CONCURRENT_STREAMS 來限制)。而且,域名分片在 HTTP/2 中還會損害性能,因為它創建了額外的 TCP 連接,妨礙 HTTP/2 為資源進行優先級排序。

當前對于 HTTP/1.1 的最佳實踐是限制域名分片為 2 個域名。好消息是為了減少工作并在 HTTP/1.1 和 HTTP/2 都能達到很好的效果,有方法可以讓 HTTP/2 合并你的連接,具體方法見 Google 家的 slide 26

實現

可喜的是,現在已經有大量的 HTTP/2 的服務器端實現了,涵蓋了多種語言,參見
Implementations

Reference

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容

  • 一、概念(載錄于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434閱讀 8,409評論 6 152
  • Http協議詳解 標簽(空格分隔): Linux 聲明:本片文章非原創,內容來源于博客園作者MIN飛翔的HTTP協...
    Sivin閱讀 5,245評論 3 82
  • 1. 網絡基礎TCP/IP HTTP基于TCP/IP協議族,HTTP屬于它內部的一個子集。 把互聯網相關聯的協議集...
    yozosann閱讀 3,455評論 0 20
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,797評論 18 139
  • 大家都知道網絡營銷是越來越重要,然而競爭越來越大,運營成本越來越高,內容營銷好像也越來越不管用,然而內容營銷又越來...
    企邦在線閱讀 581評論 0 0