「查缺補漏」鞏固你的HTTP知識體系

前言

此次梳理的篇幅主要是涉及網絡部分,包括HTTP等,對鞏固本身的網絡知識體系也是頗有幫助的,進一步的對性能優化而言也是幫助很大的。html

但更多的是拋磚引玉,但願對大家有所幫助。node

感謝掘友的鼓勵與支持🌹🌹🌹,往期文章都在最後梳理出來了(●'◡'●)git

接下來就以問題的形式展開梳理👇github

談一談HTTP協議優缺點

超文本傳輸協議,HTTP 是一個在計算機世界裏專門在兩點之間傳輸文字、圖片、音頻、視頻等超文本數據的約定和規範web

HTTP 特色

  1. 靈活可擴展。一個是語法上只規定了基本格式,空格分隔單詞,換行分隔字段等。另一個就是傳輸形式上不只能夠傳輸文本,還能夠傳輸圖片,視頻等任意數據。
  2. 請求-應答模式,一般而言,就是一方發送消息,另一方要接受消息,或者是作出相應等。
  3. 可靠傳輸,HTTP是基於TCP/IP,所以把這一特性繼承了下來。
  4. 無狀態,這個分場景回答便可。

HTTP 缺點

  1. 無狀態,有時候,須要保存信息,好比像購物系統,須要保留下顧客信息等等,另一方面,有時候,無狀態也會減小網絡開銷,好比相似直播行業這樣子等,這個仍是分場景來講。
  2. 明文傳輸,即協議裏的報文(主要指的是頭部)不使用二進制數據,而是文本形式。這讓HTTP的報文信息暴露給了外界,給攻擊者帶來了便利。
  3. 隊頭阻塞,當http開啓長鏈接時,共用一個TCP鏈接,當某個請求時間過長時,其餘的請求只能處於阻塞狀態,這就是隊頭阻塞問題。

HTTP/1.0 HTTP1.1 HTTP2.0版本之間的差別

HTTP 0.9

  • 1991年,原型版本,功能簡陋,只有一個命令GET,只支持純文本內容,該版本已過期。

HTTP 1.0

  • 任何格式的內容均可以發送,這使得互聯網不只能夠傳輸文字,還能傳輸圖像、視頻、二進制等文件。
  • 除了GET命令,還引入了POST命令和HEAD命令。
  • http請求和迴應的格式改變,除了數據部分,每次通訊都必須包括頭信息(HTTP header),用來描述一些元數據。
  • 只使用 header 中的 If-Modified-Since 和 Expires 做爲緩存失效的標準。
  • 不支持斷點續傳,也就是說,每次都會傳送所有的頁面和數據。
  • 一般每臺計算機只能綁定一個 IP,因此請求消息中的 URL 並無傳遞主機名(hostname)

HTTP 1.1

http1.1是目前最爲主流的http協議版本,從1999年發佈至今,還是主流的http協議版本。面試

  • 引入了持久鏈接( persistent connection),即TCP鏈接默認不關閉,能夠被多個請求複用,不用聲明Connection: keep-alive。長鏈接的鏈接時長能夠經過請求頭中的 keep-alive 來設置
  • 引入了管道機制( pipelining),即在同一個TCP鏈接裏,客戶端能夠同時發送多個 請求,進一步改進了HTTP協議的效率。
  • HTTP 1.1 中新增長了 E-tag,If-Unmodified-Since, If-Match, If-None-Match 等緩存控制標頭來控制緩存失效。
  • 支持斷點續傳,經過使用請求頭中的 Range 來實現。
  • 使用了虛擬網絡,在一臺物理服務器上能夠存在多個虛擬主機(Multi-homed Web Servers),而且它們共享一個IP地址。
  • 新增方法:PUT、 PATCH、 OPTIONS、 DELETE。

http1.x版本問題

  • 在傳輸數據過程當中,全部內容都是明文,客戶端和服務器端都沒法驗證對方的身份,沒法保證數據的安全性。
  • HTTP/1.1 版本默認容許複用TCP鏈接,可是在同一個TCP鏈接裏,全部數據通訊是按次序進行的,服務器一般在處理完一個迴應後,纔會繼續去處理下一個,這樣子就會形成隊頭阻塞。
  • http/1.x 版本支持Keep-alive,用此方案來彌補建立屢次鏈接產生的延遲,可是一樣會給服務器帶來壓力,而且的話,對於單文件被不斷請求的服務,Keep-alive會極大影響性能,由於它在文件被請求以後還保持了沒必要要的鏈接很長時間。

HTTP 2.0

  • 二進制分幀 這是一次完全的二進制協議,頭信息和數據體都是二進制,而且統稱爲"幀":頭信息幀和數據幀。
  • 頭部壓縮 HTTP 1.1版本會出現 User-Agent、Cookie、Accept、Server、Range 等字段可能會佔用幾百甚至幾千字節,而 Body 卻常常只有幾十字節,因此致使頭部偏重。HTTP 2.0 使用 HPACK 算法進行壓縮。
  • 多路複用 複用TCP鏈接,在一個鏈接裏,客戶端和瀏覽器均可以同時發送多個請求或迴應,且不用按順序一一對應,這樣子解決了隊頭阻塞的問題。
  • 服務器推送 容許服務器未經請求,主動向客戶端發送資源,即服務器推送。
  • 請求優先級 能夠設置數據幀的優先級,讓服務端先處理重要資源,優化用戶體驗。

談一談你對HTTP/2理解

頭部壓縮

HTTP 1.1版本會出現 User-Agent、Cookie、Accept、Server、Range 等字段可能會佔用幾百甚至幾千字節,而 Body 卻常常只有幾十字節,因此致使頭部偏重。算法

HTTP 2.0 使用 HPACK 算法進行壓縮。跨域

那咱們看看HPACK算法吧👇數組

從上面看,咱們能夠看到相似於索引表,每一個索引表對應一個值,好比索引爲2對應頭部中的method頭部信息,這樣子的話,在傳輸的時候,不在是傳輸對應的頭部信息了,而是傳遞索引,對於以前出現過的頭部信息,只須要把索引(好比1,2,...)傳給對方便可,對方拿到索引查表就好了。瀏覽器

這種傳索引的方式,能夠說讓請求頭字段獲得極大程度的精簡和複用。

其次是對於整數和字符串進行哈夫曼編碼,哈夫曼編碼的原理就是先將全部出現的字符創建一張索引表,而後讓出現次數多的字符對應的索引儘量短,傳輸的時候也是傳輸這樣的索引序列,能夠達到很是高的壓縮率。

多路複用

HTTP 1.x 中,若是想併發多個請求,必須使用多個 TCP 連接,且瀏覽器爲了控制資源,還會對單個域名有 6-8個的TCP連接請求限制。

HTTP2中:

  • 同域名下全部通訊都在單個鏈接上完成。
  • 單個鏈接能夠承載任意數量的雙向數據流。
  • 數據流以消息的形式發送,而消息又由一個或多個幀組成,多個幀之間能夠亂序發送,由於根據幀首部的流標識能夠從新組裝,也就是Stream ID,流標識符,有了它,接收方就能從亂序的二進制幀中選擇ID相同的幀,按照順序組裝成請求/響應報文。

服務器推送

瀏覽器發送一個請求,服務器主動向瀏覽器推送與這個請求相關的資源,這樣瀏覽器就不用發起後續請求。

相比較http/1.1的優點👇

  • 推送資源能夠由不一樣頁面共享
  • 服務器能夠按照優先級推送資源
  • 客戶端能夠緩存推送的資源
  • 客戶端能夠拒收推送過來的資源

二進制分幀

以前是明文傳輸,不方便計算機解析,對於回車換行符來講究竟是內容仍是分隔符,都須要內部狀態機去識別,這樣子效率低,HTTP/2採用二進制格式,所有傳輸01串,便於機器解碼。

這樣子一個報文格式就被拆分爲一個個二進制幀,用Headers幀存放頭部字段,Data幀存放請求體數據。這樣子的話,就是一堆亂序的二進制幀,它們不存在前後關係,所以不須要排隊等待,解決了HTTP隊頭阻塞問題。

在客戶端與服務器之間,雙方均可以互相發送二進制幀,這樣子雙向傳輸的序列,稱爲,因此HTTP/2中以流來表示一個TCP鏈接上進行多個數據幀的通訊,這就是多路複用概念。

那亂序的二進制幀,是如何組裝成對於的報文呢?

  • 所謂的亂序,值的是不一樣ID的Stream是亂序的,對於同一個Stream ID的幀是按順序傳輸的。
  • 接收方收到二進制幀後,將相同的Stream ID組裝成完整的請求報文和響應報文。
  • 二進制幀中有一些字段,控制着優先級流量控制等功能,這樣子的話,就能夠設置數據幀的優先級,讓服務器處理重要資源,優化用戶體驗。

介紹一下HTTP 常見狀態碼

RFC 規定 HTTP 的狀態碼爲三位數,第一個數字定義了響應的類別,被分爲五類:

  • 1xx: 表明請求已被接受,須要繼續處理。
  • 2xx: 表示成功狀態。
  • 3xx: 重定向狀態。
  • 4xx: 客戶端錯誤。
  • 5xx: 服務器端錯誤。

1xx 信息類

接受的請求正在處理,信息類狀態碼。

2xx 成功

  • 200 OK 表示從客戶端發來的請求在服務器端被正確請求。
  • 204 No content,表示請求成功,但沒有資源可返回。
  • 206 Partial Content,該狀態碼錶示客戶端進行了範圍請求,而服務器成功執行了這部分的 GET 請求 響應報文中包含由 Content-Range 指定範圍的實體內容。

3xx 重定向

  • 301 moved permanently,永久性重定向,表示資源已被分配了新的 URL,這時應該按 Location 首部字段提示的 URI 從新保存。
  • 302 found,臨時性重定向,表示資源臨時被分配了新的 URL。
  • 303 see other,表示資源存在着另外一個 URL,應使用 GET 方法獲取資源。
  • 304 not modified,當協商緩存命中時會返回這個狀態碼。
  • 307 temporary redirect,臨時重定向,和302含義相同,不會改變method

當 30一、30二、303 響應狀態碼返回時,幾乎全部的瀏覽器都會把 POST 改爲 GET,並刪除請求報文內的主體,以後請求會自動再次發送 30一、302 標準是禁止將 POST 方法改變成 GET 方法的,但實際使用時你們都會這麼作

4XX 客戶端錯誤

  • 400 bad request,請求報文存在語法錯誤。
  • 401 unauthorized,表示發送的請求須要有經過 HTTP 認證的認證信息。
  • 403 forbidden,表示對請求資源的訪問被服務器拒絕。
  • 404 not found,表示在服務器上沒有找到請求的資源。
  • 405 Method Not Allowed,服務器禁止使用該方法,客戶端能夠經過options方法來查看服務器容許的訪問方法,以下 👇
Access-Control-Allow-Methods →GET,HEAD,PUT,PATCH,POST,DELETE
複製代碼

5XX 服務器錯誤

  • 500 internal sever error,表示服務器端在執行請求時發生了錯誤。
  • 502 Bad Gateway,服務器自身是正常的,訪問的時候出了問題,具體啥錯誤咱們不知道。
  • 503 service unavailable,代表服務器暫時處於超負載或正在停機維護,沒法處理請求。

DNS如何工做的

DNS 協議提供的是一種主機名到 IP 地址的轉換服務,就是咱們常說的域名系統。是應用層協議,一般該協議運行在UDP協議之上,使用的是53端口號。

咱們經過一張圖來看看它的查詢過程吧👇

這張圖很生動的展現了DNS在本地DNS服務器是如何查詢的,通常向本地DNS服務器發送請求是遞歸查詢的

本地 DNS 服務器向其餘域名服務器請求的過程是迭代查詢的過程👇

DNS查詢
DNS查詢

遞歸查詢和迭代查詢

  • 遞歸查詢指的是查詢請求發出後,域名服務器代爲向下一級域名服務器發出請求,最後向用戶返回查詢的最終結果。使用遞歸 查詢,用戶只須要發出一次查詢請求。

  • 迭代查詢指的是查詢請求後,域名服務器返回單次查詢的結果。下一級的查詢由用戶本身請求。使用迭代查詢,用戶須要發出 屢次的查詢請求。

因此通常而言,本地服務器查詢是遞歸查詢,而本地 DNS 服務器向其餘域名服務器請求的過程是迭代查詢的過程

DNS緩存

緩存也很好理解,在一個請求中,當某個DNS服務器收到一個DNS回答後,它可以回答中的信息緩存在本地存儲器中。返回的資源記錄中的 TTL 表明了該條記錄的緩存的時間。

DNS實現負載平衡

它是如何實現負載均衡的呢?首先咱們得清楚DNS 是能夠用於在冗餘的服務器上實現負載平衡。

**緣由:**這是由於通常的大型網站使用多臺服務器提供服務,所以一個域名可能會對應 多個服務器地址。

舉個例子來講👇

  • 當用戶發起網站域名的 DNS 請求的時候,DNS 服務器返回這個域名所對應的服務器 IP 地址的集合
  • 在每一個回答中,會循環這些 IP 地址的順序,用戶通常會選擇排在前面的地址發送請求。
  • 以此將用戶的請求均衡的分配到各個不一樣的服務器上,這樣來實現負載均衡。

總結

  • DNS域名系統,是應用層協議,運行UDP協議之上,使用端口43。
  • 查詢過程,本地查詢是遞歸查詢,依次經過瀏覽器緩存 —>> 本地hosts文件 —>> 本地DNS解析器 —>>本地DNS服務器 —>> 其餘域名服務器請求。 接下來的過程就是迭代過程。
  • 遞歸查詢通常而言,發送一次請求就夠,迭代過程須要用戶發送屢次請求。

DNS 爲何使用 UDP 協議做爲傳輸層協議?

DNS 使用 UDP 協議做爲傳輸層協議的主要緣由是爲了不使用 TCP 協議時形成的鏈接時延。

  • 爲了獲得一個域名的 IP 地址,每每會向多個域名服務器查詢,若是使用 TCP 協議,那麼每次請求都會存在鏈接時延,這樣使 DNS 服務變得很慢。
  • 大多數的地址查詢請求,都是瀏覽器請求頁面時發出的,這樣會形成網頁的等待時間過長。

介紹一下Connection:keep-alive

什麼是keep-alive

咱們知道HTTP協議採用「請求-應答」模式,當使用普通模式,即非KeepAlive模式時,每一個請求/應答客戶和服務器都要新建一個鏈接,完成 以後當即斷開鏈接(HTTP協議爲無鏈接的協議);

當使用Keep-Alive模式(又稱持久鏈接、鏈接重用)時,Keep-Alive功能使客戶端到服 務器端的鏈接持續有效,當出現對服務器的後繼請求時,Keep-Alive功能避免了創建或者從新創建鏈接。

爲何要使用keep-alive

keep-alive技術的建立目的,能在屢次HTTP以前重用同一個TCP鏈接,從而減小建立/關閉多個 TCP 鏈接的開銷(包括響應時間、CPU 資源、減小擁堵等),參考以下示意圖(來源:維基百科):

客戶端如何開啓

在HTTP/1.0協議中,默認是關閉的,須要在http頭加入"Connection: Keep-Alive」,才能啓用Keep-Alive;

Connection: keep-alive
複製代碼

http 1.1中默認啓用Keep-Alive,若是加入"Connection: close 「,才關閉。

Connection: close
複製代碼

目前大部分瀏覽器都是用http1.1協議,也就是說默認都會發起Keep-Alive的鏈接請求了,因此是否能完成一個完整的Keep- Alive鏈接就看服務器設置狀況。


介紹HTTP 緩存策略

這個跟以前的瀏覽器緩存原理同樣,我直接拿我以前梳理過的吧。

我在我以前的那一篇中已經詳細的說過了,點這裏傳送門聊一聊瀏覽器緩存

咱們來梳理一下吧👇

強緩存

強緩存兩個相關字段,ExpiresCache-Control

強緩存分爲兩種狀況,一種是發送HTTP請求,一種不須要發送。

首先檢查強緩存,這個階段**不須要發送HTTP請求。**經過查找不一樣的字段來進行,不一樣的HTTP版本因此不一樣。

  • HTTP1.0版本,使用的是Expires,HTTP1.1使用的是Cache-Control

Expires

Expires即過時時間,時間是相對於服務器的時間而言的,存在於服務端返回的響應頭中,在這個過時時間以前能夠直接從緩存裏面獲取數據,無需再次請求。好比下面這樣:

Expires:Mon, 29 Jun 2020 11:10:23 GMT
複製代碼

表示該資源在2020年7月29日11:10:23過時,過時時就會從新向服務器發起請求。

這個方式有一個問題:服務器的時間和瀏覽器的時間可能並不一致,因此HTTP1.1提出新的字段代替它。

Cache-Control

HTTP1.1版本中,使用的就是該字段,這個字段採用的時間是過時時長,對應的是max-age。

Cache-Control:max-age=6000
複製代碼

上面表明該資源返回後6000秒,能夠直接使用緩存。

固然了,它還有其餘不少關鍵的指令,梳理了幾個重要的👇

注意點:

  • 當Expires和Cache-Control同時存在時,優先考慮Cache-Control。
  • 固然了,當緩存資源失效了,也就是沒有命中強緩存,接下來就進入協商緩存👇

協商緩存

強緩存失效後,瀏覽器在請求頭中攜帶響應的緩存Tag來向服務器發送請求,服務器根據對應的tag,來決定是否使用緩存。

緩存分爲兩種,Last-ModifiedETag。二者各有優點,並不存在誰對誰有絕對的優點,與上面所講的強緩存兩個Tag所不一樣。

Last-Modified

這個字段表示的是最後修改時間。在瀏覽器第一次給服務器發送請求後,服務器會在響應頭中加上這個字段。

瀏覽器接收到後,若是再次請求,會在請求頭中攜帶If-Modified-Since字段,這個字段的值也就是服務器傳來的最後修改時間。

服務器拿到請求頭中的If-Modified-Since的字段後,其實會和這個服務器中該資源的最後修改時間對比:

  • 若是請求頭中的這個值小於最後修改時間,說明是時候更新了。返回新的資源,跟常規的HTTP請求響應的流程同樣。
  • 不然返回304,告訴瀏覽器直接使用緩存。

ETag

ETag是服務器根據當前文件的內容,對文件生成惟一的標識,好比MD5算法,只要裏面的內容有改動,這個值就會修改,服務器經過把響應頭把該字段給瀏覽器。

瀏覽器接受到ETag值,會在下次請求的時候,將這個值做爲If-None-Match這個字段的內容,發給服務器。

服務器接收到If-None-Match後,會跟服務器上該資源的ETag進行比對👇

  • 若是二者同樣的話,直接返回304,告訴瀏覽器直接使用緩存
  • 若是不同的話,說明內容更新了,返回新的資源,跟常規的HTTP請求響應的流程同樣

二者對比

  • 性能上,Last-Modified優於ETagLast-Modified記錄的是時間點,而Etag須要根據文件的MD5算法生成對應的hash值。
  • 精度上,ETag優於Last-ModifiedETag按照內容給資源帶上標識,能準確感知資源變化,Last-Modified在某些場景並不能準確感知變化,好比👇
    • 編輯了資源文件,可是文件內容並無更改,這樣也會形成緩存失效。
    • Last-Modified 可以感知的單位時間是秒,若是文件在 1 秒內改變了屢次,那麼這時候的 Last-Modified 並無體現出修改了。

最後,若是兩種方式都支持的話,服務器會優先考慮ETag

緩存位置

接下來咱們考慮使用緩存的話,緩存的位置在哪裏呢?

瀏覽器緩存的位置的話,能夠分爲四種,優先級從高到低排列分別👇

  • Service Worker
  • Memory Cache
  • Disk Cache
  • Push Cache

Service Worker

這個應用場景好比PWA,它借鑑了Web Worker思路,因爲它脫離了瀏覽器的窗體,所以沒法直接訪問DOM。它能完成的功能好比:離線緩存消息推送網絡代理,其中離線緩存就是Service Worker Cache

Memory Cache

指的是內存緩存,從效率上講它是最快的,從存活時間來說又是最短的,當渲染進程結束後,內存緩存也就不存在了。

Disk Cache

存儲在磁盤中的緩存,從存取效率上講是比內存緩存慢的,優點在於存儲容量和存儲時長。

Disk Cache VS Memory Cache

二者對比,主要的策略👇

內容使用率高的話,文件優先進入磁盤

比較大的JS,CSS文件會直接放入磁盤,反之放入內存。

Push Cache

推送緩存,這算是瀏覽器中最後一道防線吧,它是HTTP/2的內容。具體我也不是很清楚,有興趣的能夠去了解。

總結

  • 首先檢查Cache-Control, 嚐鮮,看強緩存是否可用
  • 若是可用的話,直接使用
  • 不然進入協商緩存,發送HTTP請求,服務器經過請求頭中的If-Modified-Since或者If-None-Match字段檢查資源是否更新
  • 資源更新,返回資源和200狀態碼。
  • 不然,返回304,直接告訴瀏覽器直接從緩存中去資源。

說一說HTTP 的請求方法?

  • HTTP1.0定義了三種請求方法: GET, POST 和 HEAD方法
  • HTTP1.1新增了五種請求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT

http/1.1規定了如下請求方法(注意,都是大寫):

  • GET: 請求獲取Request-URI所標識的資源
  • POST: 在Request-URI所標識的資源後附加新的數據
  • HEAD: 請求獲取由Request-URI所標識的資源的響應消息報頭
  • PUT: 請求服務器存儲一個資源,並用Request-URI做爲其標識(修改數據)
  • DELETE: 請求服務器刪除對應所標識的資源
  • TRACE: 請求服務器回送收到的請求信息,主要用於測試或診斷
  • CONNECT: 創建鏈接隧道,用於代理服務器
  • OPTIONS: 列出可對資源實行的請求方法,用來跨域請求

談一談GET 和 POST 的區別

本質上,只是語義上的區別,GET 用於獲取資源,POST 用於提交資源。

想裝逼請參考 https://zhuanlan.zhihu.com/p/22536382

具體差異👇

  • 從緩存角度看,GET 請求後瀏覽器會主動緩存,POST 默認狀況下不能。
  • 從參數角度來看,GET請求通常放在URL中,所以不安全,POST請求放在請求體中,相對而言較爲安全,可是在抓包的狀況下都是同樣的。
  • 從編碼角度看,GET請求只能經行URL編碼,只能接受ASCII碼,而POST支持更多的編碼類型且不對數據類型限值。
  • GET請求冪等,POST請求不冪等,冪等指發送 M 和 N 次請求(二者不相同且都大於1),服務器上資源的狀態一致。
  • GET請求會一次性發送請求報文,POST請求一般分爲兩個TCP數據包,首先發 header 部分,若是服務器響應 100(continue), 而後發 body 部分。

從應用場景角度來看,Get 多用於無反作用,冪等的場景,例如搜索關鍵字。Post 多用於反作用,不冪等的場景,例如註冊。


options 方法有什麼用?

  • OPTIONS 請求與 HEAD 相似,通常也是用於客戶端查看服務器的性能。

  • 這個方法會請求服務器返回該資源所支持的全部 HTTP 請求方法,該方法會用'*'來代替資源名稱,向服務器發送 OPTIONS 請求,能夠測試服務器功能是否正常。

  • JS 的 XMLHttpRequest對象進行 CORS 跨域資源共享時,對於複雜請求,就是使用 OPTIONS 方法發送嗅探請求,以判斷是否有對指定資源的訪問權限。


談一談你對URL理解

統一資源定位符的簡稱,Uniform Resource Locator,經常被稱爲網址,是因特網上標準的資源地址。

組成

通用的格式:scheme://host[:port]/path/…/?query#anchor

名稱 功能
scheme 訪問服務器以獲取資源時要使用哪一種協議,好比:http,https 和 FTP 等
host HTTP 服務器的 IP 地址或者域名
port HTTP 服務器的默認端口是 80,HTTPS默認端口是443,這種狀況下端口號能夠省略,若是使用了別的端口,必須指明。不一樣的端口,你能夠認爲是不一樣的應用程序。
path 訪問資源的路徑
query-string 發給 http 服務器的數據
anchor 錨點

舉個例子👇

https://www.baidu.com/s?tn=baidu&bar=&wd=TianTian
複製代碼

這個URL中,https就是協議,www.baidu.com就是域名,默認端口是443,/s就是請求的path,tn=baidu&bar=&wd=TianTian這個就是query

URL 編碼

  • URL 只能使用 ASCII 字符集來經過因特網進行發送。
  • 因爲 URL 經常會包含 ASCII 集合以外的字符,URL 必須轉換爲有效的 ASCII 格式。
  • URL 編碼使用 "%" 其後跟隨兩位的十六進制數來替換非 ASCII 字符。
  • URL 不能包含空格。URL 編碼一般使用 + 來替換空格。

舉個例子👇

每天轉換爲有效的ASCII格式就是%CC%EC%CC%EC


談一談隊頭阻塞問題

什麼是隊頭阻塞?

對於每個HTTP請求而言,這些任務是會被放入一個任務隊列中串行執行的,一旦隊首任務請求太慢時,就會阻塞後面的請求處理,這就是HTTP隊頭阻塞問題。

有什麼解決辦法嗎👇

併發鏈接

咱們知道對於一個域名而言,是容許分配多個長鏈接的,那麼能夠理解成增長了任務隊列,也就是說不會致使一個任務阻塞了該任務隊列的其餘任務,在RFC規範中規定客戶端最多併發2個鏈接,不過實際狀況就是要比這個還要多,舉個例子,Chrome中是6個。

域名分片

顧名思義,咱們能夠在一個域名下分出多個二級域名出來,而它們最終指向的仍是同一個服務器,這樣子的話就能夠併發處理的任務隊列更多,也更好的解決了隊頭阻塞的問題。

舉個例子,好比TianTian.com,能夠分出不少二級域名,好比Day1.TianTian.comDay2.TianTian.com,Day3.TianTian.com,這樣子就能夠有效解決隊頭阻塞問題。


談一談HTTP數據傳輸

大概遇到的狀況就分爲定長數據不定長數據的處理吧。

定長數據

對於定長的數據包而言,發送端在發送數據的過程當中,須要設置Content-Length,來指明發送數據的長度。

固然了若是採用了Gzip壓縮的話,Content-Length設置的就是壓縮後的傳輸長度。

咱們還須要知道的是👇

  • Content-Length若是存在而且有效的話,則必須和消息內容的傳輸長度徹底一致,也就是說,若是太短就會截斷,過長的話,就會致使超時。
  • 若是採用短連接的話,直接能夠經過服務器關閉鏈接來肯定消息的傳輸長度。
  • 那麼在HTTP/1.0以前的版本中,Content-Length字段無關緊要,由於一旦服務器關閉鏈接,咱們就能夠獲取到傳輸數據的長度了。
  • 在HTTP/1.1版本中,若是是Keep-alive的話,chunked優先級高於Content-Length,如果非Keep-alive,跟前面狀況同樣,Content-Length無關緊要。

那怎麼來設置Content-Length

舉個例子來看看👇

const server = require('http').createServer();
server.on('request', (req, res) => {
  if(req.url === '/index') {
   // 設置數據類型
    res.setHeader('Content-Type''text/plain');
    res.setHeader('Content-Length', 10);
    res.write("你好,使用的是Content-Length設置傳輸數據形式");
  }
})

server.listen(3000, () => {
  console.log("成功啓動--TinaTian");
})

複製代碼

不定長數據

如今採用最多的就是HTTP/1.1版本,來完成傳輸數據,在保存Keep-alive狀態下,當數據是不定長的時候,咱們須要設置新的頭部字段👇

Transfer-Encoding: chunked
複製代碼

經過chunked機制,能夠完成對不定長數據的處理,固然了,你須要知道的是

  • 若是頭部信息中有Transfer-Encoding,優先採用Transfer-Encoding裏面的方法來找到對應的長度。
  • 若是設置了Transfer-Encoding,那麼Content-Length將被忽視。
  • 使用長鏈接的話,會持續的推送動態內容。

那咱們來模擬一下吧👇

const server = require('http').createServer();
server.on('request', (req, res) => {
  if(req.url === '/index') {
   // 設置數據類型
    res.setHeader('Content-Type''text/html; charset=utf8');
    res.setHeader('Content-Length', 10);
    res.setHeader('Transfer-Encoding''chunked');
    
    res.write("你好,使用的是Transfer-Encoding設置傳輸數據形式");
    setTimeout(() => {
      res.write("第一次傳輸數據給您<br/>");
    }, 1000);
    res.write("騷等一下");
    setTimeout(() => {
      res.write("第一次傳輸數據給您");
      res.end()
    }, 3000);
  }
})

server.listen(3000, () => {
  console.log("成功啓動--TinaTian");
})

複製代碼

上面使用的是nodejs中http模塊,有興趣的小夥伴能夠去試一試,以上就是HTTP對定長數據不定長數據傳輸過程當中的處理手段。


介紹一下HTTPS和HTTP區別

HTTPS 要比 HTTPS 多了 secure 安全性這個概念,實際上, HTTPS 並非一個新的應用層協議,它其實就是 HTTP + TLS/SSL 協議組合而成,而安全性的保證正是 SSL/TLS 所作的工做。

SSL

安全套接層(Secure Sockets Layer)

TLS

(傳輸層安全,Transport Layer Security)

如今主流的版本是 TLS/1.2, 以前的 TLS1.0、TLS1.1 都被認爲是不安全的,在不久的未來會被徹底淘汰。

HTTPS 就是身披了一層 SSL 的 HTTP

HTTP與HTTPS區別
HTTP與HTTPS區別

那麼區別有哪些呢👇

  • HTTP 是明文傳輸協議,HTTPS 協議是由 SSL+HTTP 協議構建的可進行加密傳輸、身份認證的網絡協議,比 HTTP 協議安全。
  • HTTPS比HTTP更加安全,對搜索引擎更友好,利於SEO,谷歌、百度優先索引HTTPS網頁。
  • HTTPS標準端口443,HTTP標準端口80。
  • HTTPS須要用到SSL證書,而HTTP不用。

我以爲記住如下兩點HTTPS主要做用就行👇

  1. 對數據進行加密,並創建一個信息安全通道,來保證傳輸過程當中的數據安全;
  2. 對網站服務器進行真實身份認證。

介紹一個HTTPS工做原理

上一節來看,咱們能夠把HTTPS理解成HTTPS = HTTP + SSL/TLS

TLS/SSL 的功能實現主要依賴於三類基本算法:散列函數對稱加密非對稱加密,其利用非對稱加密實現身份認證和密鑰協商,對稱加密算法採用協商的密鑰對數據加密,基於散列函數驗證信息的完整性。

對稱加密

加密和解密用同一個祕鑰的加密方式叫作對稱加密。Client客戶端和Server端共用一套密鑰,這樣子的加密過程彷佛很讓人理解,可是隨之會產生一些問題。

問題一: WWW萬維網有許許多多的客戶端,不可能都用祕鑰A進行信息加密,這樣子很不合理,因此解決辦法就是使用一個客戶端使用一個密鑰進行加密。

問題二:既然不一樣的客戶端使用不一樣的密鑰,那麼對稱加密的密鑰如何傳輸? 那麼解決的辦法只能是一端生成一個祕鑰,而後經過HTTP傳輸給另外一端,那麼這樣子又會產生新的問題。

問題三: 這個傳輸密鑰的過程,又如何保證加密?若是被中間人攔截,密鑰也會被獲取, 那麼你會說對密鑰再進行加密,那又怎麼保存對密鑰加密的過程,是加密的過程?

到這裏,咱們彷佛想明白了,使用對稱加密的方式,行不通,因此咱們須要採用非對稱加密👇

非對稱加密

經過上面的分析,對稱加密的方式行不通,那麼咱們來梳理一下非對稱加密。採用的算法是RSA,因此在一些文章中也會看見傳統RSA握手,基於如今TLS主流版本是1.2,因此接下來梳理的是TLS/1.2握手過程

非對稱加密中,咱們須要明確的點是👇

  • 有一對祕鑰,公鑰私鑰
  • 公鑰加密的內容,只有私鑰能夠解開,私鑰加密的內容,全部的公鑰均可以解開,這裏說的公鑰均可以解開,指的是一對祕鑰
  • 公鑰能夠發送給全部的客戶端,私鑰只保存在服務器端。

主要工做流程

梳理起來,能夠把TLS 1.2 握手過程分爲主要的五步👇

圖片內容來自浪裏行舟

步驟(1)

Client發起一個HTTPS請求,鏈接443端口。這個過程能夠理解成是請求公鑰的過程

步驟(2)

Server端收到請求後,經過第三方機構私鑰加密,會把數字證書(也能夠認爲是公鑰證書)發送給Client。

步驟(3)

  • 瀏覽器安裝後會自動帶一些權威第三方機構公鑰,使用匹配的公鑰對數字簽名進行解密。
  • 根據簽名生成的規則對網站信息進行本地簽名生成,而後二者比對。
  • 經過比對二者簽名,匹配則說明認證經過,不匹配則獲取證書失敗。

步驟(4)

在安全拿到服務器公鑰後,客戶端Client隨機生成一個對稱密鑰,使用服務器公鑰(證書的公鑰)加密這個對稱密鑰,發送給Server(服務器)。

步驟(5)

Server(服務器)經過本身的私鑰,對信息解密,至此獲得了對稱密鑰,此時二者都擁有了相同的對稱密鑰

接下來,就能夠經過該對稱密鑰對傳輸的信息加密/解密啦,從上面圖舉個例子👇

  • Client用戶使用該對稱密鑰加密'明文內容B',發送給Server(服務器)
  • Server使用該對稱密鑰進行解密消息,獲得明文內容B。

接下來考慮一個問題,若是公鑰被中間人拿到纂改怎麼辦呢?

如下圖片來自leocoder

中間人獲取公鑰
中間人獲取公鑰

客戶端可能拿到的公鑰是假的,解決辦法是什麼呢?

第三方認證

客戶端沒法識別傳回公鑰是中間人的,仍是服務器的,這是問題的根本,咱們是否是能夠經過某種規範可讓客戶端和服務器都遵循某種約定呢?那就是經過第三方認證的方式

在HTTPS中,經過 證書 + 數字簽名來解決這個問題。

這裏惟一不一樣的是,假設對網站信息加密的算法是MD5,經過MD5加密後,而後經過第三方機構的私鑰再次對其加密,生成數字簽名

這樣子的話,數字證書包含有兩個特別重要的信息👉某網站公鑰+數字簽名

咱們再次假設中間人截取到服務器的公鑰後,去替換成本身的公鑰,由於有數字簽名的存在,這樣子客戶端驗證發現數字簽名不匹配,這樣子就防止中間人替換公鑰的問題。

那麼客戶端是如何去對比二者數字簽名的呢?

  • 瀏覽器會去安裝一些比較權威的第三方認證機構的公鑰,好比VeriSign、Symantec以及GlobalSign等等。
  • 驗證數字簽名的時候,會直接從本地拿到相應的第三方的公鑰,對私鑰加密後的數字簽名進行解密獲得真正的簽名。
  • 而後客戶端利用簽名生成規則進行簽名生成,看兩個簽名是否匹配,若是匹配認證經過,不匹配則獲取證書失敗。

數字簽名做用

數字簽名:將網站的信息,經過特定的算法加密,好比MD5,加密以後,再經過服務器的私鑰進行加密,造成加密後的數字簽名

第三方認證機構是一個公開的平臺,中間人能夠去獲取。

若是沒有數字簽名的話,這樣子能夠就會有下面狀況👇

從上面咱們知道,若是只是對網站信息進行第三方機構私鑰加密的話,仍是會受到欺騙。

由於沒有認證,因此中間人也向第三方認證機構進行申請,而後攔截後把全部的信息都替換成本身的,客戶端仍然能夠解密,而且沒法判斷這是服務器的仍是中間人的,最後形成數據泄露。

總結

  • HTTPS就是使用SSL/TLS協議進行加密傳輸
  • 大體流程:客戶端拿到服務器的公鑰(是正確的),而後客戶端隨機生成一個對稱加密的祕鑰,使用該公鑰加密,傳輸給服務端,服務端再經過解密拿到該對稱祕鑰,後續的全部信息都經過該對稱祕鑰進行加密解密,完成整個HTTPS的流程。
  • 第三方認證,最重要的是數字簽名,避免了獲取的公鑰是中間人的。

SSL 鏈接斷開後如何恢復?

一共有兩種方法來恢復斷開的 SSL 鏈接,一種是使用 session ID,一種是 session ticket。

經過session ID

使用 session ID 的方式,每一次的會話都有一個編號,當對話中斷後,下一次從新鏈接時,只要客戶端給出這個編號,服務器若是有這個編號的記錄,那麼雙方就能夠繼續使用之前的祕鑰,而不用從新生成一把。目前全部的瀏覽器都支持這一種方法。可是這種方法有一個缺點是,session ID 只可以存在一臺服務器上,若是咱們的請求經過負載平衡被轉移到了其餘的服務器上,那麼就沒法恢復對話。

經過session ticket

另外一種方式是 session ticket 的方式,session ticket 是服務器在上一次對話中發送給客戶的,這個 ticket 是加密的,只有服務器可以解密,裏面包含了本次會話的信息,好比對話祕鑰和加密方法等。這樣無論咱們的請求是否轉移到其餘的服務器上,當服務器將 ticket 解密之後,就可以獲取上次對話的信息,就不用從新生成對話祕鑰了。

短輪詢、長輪詢和 WebSocket 間的區別?

短輪詢

短輪詢的基本思路:

  • 瀏覽器每隔一段時間向瀏覽器發送 http 請求,服務器端在收到請求後,不管是否有數據更新,都直接進行 響應。
  • 這種方式實現的即時通訊,本質上仍是瀏覽器發送請求,服務器接受請求的一個過程,經過讓客戶端不斷的進行請求,使得客戶端可以模擬實時地收到服務器端的數據的變化。

優缺點👇

  • 優勢是比較簡單,易於理解。

  • 缺點是這種方式因爲須要不斷的創建 http 鏈接,嚴重浪費了服務器端和客戶端的資源。當用戶增長時,服務器端的壓力就會變大,這是很不合理的。

長輪詢

長輪詢的基本思路:

  • 首先由客戶端向服務器發起請求,當服務器收到客戶端發來的請求後,服務器端不會直接進行響應,而是先將 這個請求掛起,而後判斷服務器端數據是否有更新。

  • 若是有更新,則進行響應,若是一直沒有數據,則到達必定的時間限制才返回。客戶端 JavaScript 響應處理函數會在處理完服務器返回的信息後,再次發出請求,從新創建鏈接。

優缺點👇

  • 長輪詢和短輪詢比起來,它的優勢是明顯減小了不少沒必要要的 http 請求次數,相比之下節約了資源。

  • 長輪詢的缺點在於,鏈接掛起也會致使資源的浪費。

WebSocket

  • WebSocket 是 Html5 定義的一個新協議,與傳統的 http 協議不一樣,該協議容許由服務器主動的向客戶端推送信息。
  • 使用 WebSocket 協議的缺點是在服務器端的配置比較複雜。WebSocket 是一個全雙工的協議,也就是通訊雙方是平等的,能夠相互發送消息。

說一說正向代理和反向代理

正向代理

咱們常說的代理也就是指正向代理,正向代理的過程,它隱藏了真實的請求客戶端,服務端不知道真實的客戶端是誰,客戶端請求的服務都被代理服務器代替來請求。

反向代理

這種代理模式下,它隱藏了真實的服務端,當咱們向一個網站發起請求的時候,背後可能有成千上萬臺服務器爲咱們服務,具體是哪一臺,咱們不清楚,咱們只須要知道反向代理服務器是誰就行,並且反向代理服務器會幫咱們把請求轉發到真實的服務器那裏去,通常而言反向代理服務器通常用來實現負載平衡。

負載平衡的兩種實現方式?

  • 一種是使用反向代理的方式,用戶的請求都發送到反向代理服務上,而後由反向代理服務器來轉發請求到真實的服務器上,以此來實現集羣的負載平衡。

  • 另外一種是 DNS 的方式,DNS 能夠用於在冗餘的服務器上實現負載平衡。由於如今通常的大型網站使用多臺服務器提供服務,所以一個域名可能會對應多個服務器地址。當用戶向網站域名請求的時候,DNS 服務器返回這個域名所對應的服務器 IP 地址的集合,但在每一個回答中,會循環這些 IP 地址的順序,用戶通常會選擇排在前面的地址發送請求。以此將用戶的請求均衡的分配到各個不一樣的服務器上,這樣來實現負載均衡。這種方式有一個缺點就是,因爲 DNS 服務器中存在緩存,因此有可能一個服務器出現故障後,域名解析仍然返回的是那個 IP 地址,就會形成訪問的問題。

參考

❤️ 感謝你們

若是你以爲這篇內容對你挺有有幫助的話:

  1. 點贊支持下吧,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)
  2. 歡迎在留言區與我分享你的想法,也歡迎你在留言區記錄你的思考過程。
  3. 以爲不錯的話,也能夠閱讀TianTian近期梳理的文章(感謝掘友的鼓勵與支持🌹🌹🌹):
相關文章
相關標籤/搜索