天天看點

聊聊Http/Https協定中的一些高頻面試知識點

1.什麼是Http協定?

超文本傳輸協定(英文:HyperText Transfer Protocol,縮寫:HTTP)是一種用于分布式、協作式和超媒體資訊系統的應用層協定。HTTP是網際網路的資料通信的基礎。

應用 HTTP 協定時,必定是一端擔任用戶端角色,另一端擔任伺服器端角色。

有時候,按實際情況,兩台計算機作為用戶端和伺服器端的角色有可 能會互換。但就僅從一條通信路線來說,伺服器端和用戶端的角色是确定的,而用 HTTP 協定能夠明确區分哪端是用戶端,哪端是伺服器端。

HTTP 協定規定,請求從用戶端發出,最後伺服器端響應該請求并返 回。換句話說,肯定是先從用戶端開始建立通信的,伺服器端在沒有 接收到請求之前不會發送響應。

2.HTTP的封包結構

對于 TCP 而言,在傳輸的時候分為兩個部分:TCP頭和資料部分。

而 HTTP 類似,也是header + body的結構,具體而言:起始行 + 頭部 + 空行 + 實體。

下面我們分别介紹一下:

起始行

請求封包的請示行和響應封包的起始行還是有些差別的。

對于請求封包來說,起始行如下:

GET /home HTTP/1.1
方法類型(區分大小寫) + 路徑 + http路徑           

對于響應封包來說,起始行(狀态行)如下:

HTTP/1.1 200 OK
http版本 + 狀态碼 + 原因           

要說明一點的是,在起始行中,每兩個部分之間用空格隔開,最後一個部分後面應該接一個換行,嚴格遵循ABNF文法規範。

頭部

頭部字段一般分為以下幾種:請求頭部,響應頭部,通用頭部,實體頭部

請求頭和響應頭在封包中的位置如下:

聊聊Http/Https協定中的一些高頻面試知識點

頭部字段的格式一般如下:

1.字段名不區分大小寫

2.字段名不允許出現空格,不可以出現下劃線_

3.字段名後面必須緊接着:

空行

空行用來區分開頭部和實體。

實體

指具體的資料了,也就是body部分。請求封包對應請求體, 響應封包對應響應體。

3.HTTP的請求方式

http/1.1規定了以下請求方法:

  • GET: 通常用來擷取資源
  • HEAD: 擷取資源的元資訊
  • POST: 送出資料,即上傳資料
  • PUT: 修改資料
  • DELETE: 删除資源(幾乎用不到)
  • CONNECT: 建立連接配接隧道,用于代理伺服器
  • OPTIONS: 列出可對資源實行的請求方法,用來跨域請求
  • TRACE: 追蹤請求-響應的傳輸路徑

以上八種請求方式,GET和POST是我們用的最多的兩種請求方式也是最重要的兩種。

4.GET和POST的差別

從緩存的角度,GET 請求會被浏覽器主動緩存下來,留下曆史記錄,而 POST 預設不會。

從編碼的角度,GET 隻能進行 URL 編碼,隻能接收 ASCII 字元,而 POST 沒有限制。

從參數的角度,GET 一般放在 URL 中,是以不安全,POST 放在請求體中,更适合傳輸敏感資訊。

從幂等性的角度,GET是幂等的,而POST不是。(幂等表示執行相同的操作,結果也是相同的)

從TCP的角度,GET 請求會把請求封包一次性發出去,而 POST 會分為兩個 TCP 資料包,首先發 header 部分,如果伺服器響應 100(continue), 然後發 body 部分。(火狐浏覽器除外,它的 POST 請求隻發一個 TCP 包)

5.Http的狀态碼

狀态碼的職責是當用戶端向伺服器端發送請求時,描述傳回的請求結果。借助狀态碼,使用者可以知道伺服器端是正常處理了請求,還是出現了錯誤。

一般分為以下幾種類别:

  • 1XX:為資訊性狀态碼,表示接收的請求正在處理。
  • 2XX:為成功狀态碼,表示請求正常處理完畢。
  • 3XX:為重定向狀态碼,表示需要進行附加操作以完成請求。
  • 4XX:為用戶端錯誤狀态碼,表示伺服器無法處理請求。
  • 5XX:為服務端錯誤狀态碼,伺服器處理請求出錯。

常見的狀态碼例如:

  • 200 OK 請求成功被處理,且傳回了資料。
  • 204 No Content 請求成功被處理,但是沒有資料資源要傳回。
  • 301 Moved Permanently 永久性重定向。該狀态碼表示請求的資源已被配置設定了新的 URI,以後 應使用資源現在所指的 URI。
  • 302 Found 臨時性重定向。該狀态碼表示請求的資源已被配置設定了新的 URI,希望 使用者(本次)能使用新的 URI 通路。
  • 304 Not Modified 在下面說到http對比緩存的時候會聊到,表示資源沒有被修改,可以使用緩存。
  • 400 Bad Request 表示請求封包中存在文法錯誤。當錯誤發生時,需修改請求 的内容後再次發送請求。
  • 401 Unauthorized 未認證需要認證後在重新請求。
  • 403 Forbidden 表明對請求資源的通路被伺服器拒絕了。
  • 404 Not Found 表明伺服器上無法找到請求的資源。
  • 500 Internal Server Error 表明伺服器端在執行請求時發生了錯誤。
  • 503 Service Unavailable 表明伺服器暫時處于超負載或正在進行停機維護,現在無法 處理請求。

相關視訊推薦

c++背景開發,如何讓你的http web伺服器做的與衆不同

從50道騰訊面試題,分析騰訊c++後端工程的技能樹

學習位址:C/C++Linux伺服器開發/背景架構師【零聲教育】-學習視訊教程-騰訊課堂

需要C/C++ Linux伺服器架構師學習資料加群812855908擷取(資料包括C/C++,Linux,golang技術,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協程,DPDK,ffmpeg等),免費分享

聊聊Http/Https協定中的一些高頻面試知識點

6.Http協定中重要的頭部字段

上面我們說了Http頭部字段(首部字段)一般分為四種:

1.通用首部字段:

聊聊Http/Https協定中的一些高頻面試知識點

​2.請求首部字段:

聊聊Http/Https協定中的一些高頻面試知識點

​3.響應首部字段:

聊聊Http/Https協定中的一些高頻面試知識點

​4.實體首部字段

聊聊Http/Https協定中的一些高頻面試知識點

​下面我們挑幾個經常性問道的首部字段進行說明。

(1)Cache-Control

通過指定首部字段 Cache-Control 的指令,能夠操作緩存的工作機制。

指令的參數是可選的,多個指令之間通過“,”分隔。首部字段 Cache- Control 的指令可用于請求及響應時。

Cache-Control: private, max-age=0, no-cache           

在請求中,Cache-Control有以下可選指令:

聊聊Http/Https協定中的一些高頻面試知識點

​在響應中,Cache-Control有以下可選指令:

聊聊Http/Https協定中的一些高頻面試知識點

​1.no-cache 指令:

使用 no-cache 指令的目的是為了防止從緩存中傳回過期的資源。用戶端發送的請求中如果包含 no-cache 指令,則表示用戶端将不會接收緩存過的響應。

如果伺服器傳回的響應中包含 no-cache 指令,那麼緩存伺服器不能對 資源進行緩存。源伺服器以後也将不再對緩存伺服器請求中提出的資 源有效性進行确認,且禁止其對響應資源進行緩存操作。

2.no-store 指令:

從字面意思上很容易把 no-cache 誤解成為不緩存,但事實上 no-cache 代表不緩存過期的資源,緩存會向源伺服器進行有效期确認後處理資源。no-store 才是真正地不進行緩存。

3.max-age 指令:

Cache-Control: max-age=604800(機關:秒)           

當用戶端發送的請求中包含 max-age 指令時,如果判定緩存資源的緩存時間數值比指定時間的數值更小,那麼用戶端就接收緩存的資源。

當伺服器傳回的響應中包含 max-age 指令時,緩存伺服器将不對資源的有效性再作确認,而 max-age 數值代表資源儲存為緩存的最長時間

(2)Connection

Connection 首部字段具備如下兩個作用。

1.控制不再轉發給代理的首部字段。

Connection: 不再轉發的首部字段名           

在用戶端發送請求和伺服器傳回響應内,使用 Connection 首部字 段,可控制不再轉發給代理的首部字段。

2.管理持久連接配接。

Connection: close/Keep-Alive           

HTTP 協定的初始版本中,每進行一次 HTTP 通信就要斷開一次 TCP 連接配接。如果一次性有多個Http請求,很明顯每次TCP/IP握手和揮手都會帶來一定的開銷。

HTTP/1.1 版本的預設連接配接都是持久連接配接。為此,用戶端會在持 久連接配接上連續發送請求。當伺服器端想明确斷開連接配接時,則指定 Connection 首部字段的值為 Close。

HTTP/1.1 之前的 HTTP 版本的預設連接配接都是非持久連接配接。為 此,如果想在舊版本的 HTTP 協定上維持持續連接配接,則需要指定 Connection 首部字段的值為 Keep-Alive。

(3)Transfer-Encoding

Transfer-Encoding 規定了傳輸封包主體時采用的編碼方式。

例如:

Transfer-Encoding: chunked           

當傳回的資料比較大時,如果等待生成完資料再傳輸,這樣效率比較低下。相比而言,伺服器更希望邊生成資料邊傳輸。可以在響應頭加上chunked字段辨別分塊傳輸。

設定這個字段後會自動産生兩個效果:

Content-Length 字段會被忽略。

基于長連接配接持續推送動态内容。

如何辨別傳輸完畢呢?

當傳輸完若幹個資料塊後,需要再傳輸一個空的資料塊。當用戶端收到空的資料塊時,則用戶端知道資料接收完畢。

(4)Accept

Accept 首部字段可通知伺服器,用戶端能夠處理的媒體類型及媒體類型的相對優先級。可使用 type/subtype 這種形式,一次指定多種媒體類型。

Accept: text/html,application/xhtml+xml,application/xml;q=0.           

(5)Accept-Encoding

Accept-Encoding 首部字段用來告知伺服器用戶端支援的内容編碼及内容編碼的優先級順序。可一次性指定多種内容編碼。

Accept-Encoding: gzip, deflate           

下面舉出幾個内容編碼的例子。

gzip:

由檔案壓縮程式 gzip(GNU zip)生成的編碼格式 (RFC1952),采用 Lempel-Ziv 算法(LZ77)及 32 位循環備援 校驗(Cyclic Redundancy Check,通稱 CRC)。

compress:

由 UNIX 檔案壓縮程式 compress 生成的編碼格式,采用 Lempel- Ziv-Welch 算法(LZW)。

deflate:

組合使用 zlib 格式(RFC1950)及由 deflate 壓縮算法 (RFC1951)生成的編碼格式。

identity:

不執行壓縮或不會變化的預設編碼格式

(6)Accept-Language

首部字段 Accept-Language 用來告知伺服器用戶端支援的語言指中文或英文等),以及支援的相對優先級。可一次指定多種語言。

(7)If-Modified-Since

If-Modified-Since 用于确認代理或用戶端擁有的本地資源的有效性。 擷取資源的更新日期時間,可通過确認首部字段 Last-Modified 來确定。

在指定 If-Modified-Since 字段值的日期時間之後,如果請求的資源都沒有過更新,則傳回狀态碼 304 Not Modified 的響應。否則伺服器會響應該請求。

(8)Range

Range: bytes=5001-10000           

對于隻需擷取部分資源的範圍請求,包含首部字段 Range 即可告知服 務器資源的指定範圍。上面的示例表示請求擷取從第 5001 位元組至第 10000 位元組的資源。

接收到附帶 Range 首部字段請求的伺服器,會在處理請求之後傳回狀 态碼為 206 Partial Content 的響應。無法處理該範圍請求時,則會返 回狀态碼 200 OK 的響應及全部資源。

(9)User-Agent

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/201           

User-Agent 會将建立請求的浏覽器和使用者代理名稱等資訊傳 達給伺服器。

(10)ETag

ETag: "82e22293907ce725faf67773957acd12"           

ETag 能告知用戶端實體辨別。它是一種可将資源以字元串 形式做唯一性辨別的方式。伺服器會為每份資源配置設定對應的 ETag 值。

當資源更新時,ETag 值也需要更新。 ETag 值由伺服器來配置設定。

(11)Allow

Allow: GET, HEAD           

Allow 用于通知用戶端能夠支援的指定資源的所有 HTTP 方法。當伺服器接收到不支援的 HTTP 方法時,會以狀态碼 405 Method Not Allowed 作為響應傳回。與此同時,還會把所有能支援的 HTTP 方法寫入首部字段 Allow 後傳回。

(12)Content-Encoding

Content-Encoding: gzip           

Content-Encoding 會告知用戶端伺服器對實體的主體部分選用的内容編碼方式。内容編碼是指在不丢失實體資訊的前提下所進行的壓縮。

(13)Content-Length

Content-Length: 15000           

Content-Length 表明了實體主體部分的大小(機關是字 節)。

(14)Content-Range

Content-Range: bytes 5001-10000/10000           

針對範圍請求,傳回響應時使用 Content-Range,告知用戶端作為響應傳回的實體的哪個部分符合範圍請求。字段值以位元組為機關,表示目前發送部分及整個實體大小。

(15)Content-Type

Content-Type: text/html; charset=UTF-8           

Content-Type 說明了實體主體内對象的媒體類型。和 Accept 一樣,字段值用 type/subtype 形式指派。

(16)Expires

Expires: Wed, 04 Jul 2012 08:26:05 GMT           

Expires 會将資源失效的日期告知用戶端。

如果當Cache-Control 有指定 max-age 指令時,比起Expires,會優先處理 max-age 指令。

(17)Last-Modified

Last-Modified: Wed, 23 May 2012 09:59:55 GMT           

首部字段 Last-Modified 指明資源最終修改的時間。

7.聊聊Cookie

HTTP 是一個無狀态的協定,每次 http 請求都是獨立、無關的,預設不需要保留狀态資訊。但有時候需要儲存一些狀态,怎麼辦呢?

Http引入了Cooike技術來解決上面所說的問題。Cookie 技術通過在請求和響應封包中寫入 Cookie 信 息來控制用戶端的狀态。

Cookie 本質上就是浏覽器裡面存儲的一個很小的文本檔案,内部以鍵值對的方式來存儲。

Cookie 會根據從伺服器端發送的響應封包内的一個叫做 Set-Cookie 的 首部字段資訊,通知用戶端儲存 Cookie。

當下次用戶端再往該伺服器 發送請求時,用戶端會自動在請求封包中加入 Cookie 值後發送出去。伺服器端發現用戶端發送過來的 Cookie 後,會去檢查究竟是從哪一 個用戶端發來的連接配接請求,然後對比伺服器上的記錄,最後得到之前的狀态資訊。

Cookie互動的流程大緻如下圖:

聊聊Http/Https協定中的一些高頻面試知識點

​Cookie生存周期

Cookie 的有效期可以通過Expires和Max-Age兩個屬性來設定。

Expires表示過期時間

Max-Age用的是一段時間間隔,機關是秒,從浏覽器收到封包開始計算。

若 Cookie 過期,則這個 Cookie 會被删除,并不會發送給服務端。

Cookie作用域

關于作用域也有兩個屬性: Domain和path, 給 Cookie 綁定了域名和路徑,在發送請求之前,發現域名或者路徑和這兩個屬性不比對,那麼就不會帶上 Cookie。值得注意的是,對于路徑來說,/表示域名下的任意路徑都允許使用 Cookie。

HttpOnly 屬性

Cookie 的 HttpOnly 屬性是 Cookie 的擴充功能,隻能通過 HTTP 協定傳輸,它使 JS 腳本無法獲得 Cookie。其主要目的為防止跨站腳本攻擊(Cross-site scripting,XSS)對 Cookie 的資訊竊取。

相應的,對于 CSRF 攻擊的預防,也有SameSite屬性。

Cookie 的缺點

容量缺陷:Cookie 的體積上限隻有4KB,隻能用來存儲少量的資訊。

性能缺陷:Cookie 緊跟域名,不管域名下面的某一個位址需不需要這個 Cookie ,請求都會攜帶上完整的 Cookie,這樣随着請求數的增多,其實會造成巨大的性能浪費的,因為請求攜帶了很多不必要的内容。但可以通過Domain和Path指定作用域來解決。

安全缺陷:由于 Cookie 以純文字的形式在浏覽器和伺服器中傳遞,很容易被非法使用者截獲,然後進行一系列的篡改,在 Cookie 的有效期内重新發送給伺服器,這是相當危險的。另外,在HttpOnly為 false 的情況下,Cookie 資訊能直接通過 JS 腳本來讀取。

8.聊聊Http代理

HTTP 是基于請求-響應模型的協定,一般由用戶端發請求,伺服器來進行響應。但有時候用戶端的請求并不會直接就到源伺服器。為了解決一些問題,在請求過程中,可能會有代理伺服器進行中轉。

代理伺服器的功能是什麼呢?

1.負載均衡。用戶端的請求會先到達代理伺服器,代理伺服器可以拿到這個請求之後,可以通過特定的算法分發給不同的源伺服器,讓各台源伺服器的負載盡量平均。

2.保障安全。利用心跳機制監控背景的伺服器,一旦發現故障機就将其踢出叢集。并且對于上下行的資料進行過濾,對非法 IP 限流。

3.緩存代理。将内容緩存到代理伺服器,使得用戶端可以直接從代理伺服器獲得而不用到源伺服器那裡。

9.聊聊Http緩存

HTTP 的緩存機制是依賴于請求和響應頭部裡的頭部字段的值實作的,重要的字段我們上面都有介紹到,最終響應式從緩存中取,還是從服務端重新拉取。整體流程我們還是借用一張圖簡單概括一下:

聊聊Http/Https協定中的一些高頻面試知識點

HTTP 的緩存可以分為兩種:

強制緩存:不需要服務端再次參與判斷是否繼續使用緩存,當用戶端第一次請求資料時,服務端傳回了緩存的過期時間(Expires 與 Cache-Control),沒有過期就可以繼續使用緩存,否則就不使用,無需再向服務端詢問。

對比緩存:需要服務端參與再次判斷是否繼續使用緩存,當用戶端第一次請求資料時,服務端會将緩存辨別(Last-Modified/If-Modified-Since 與 Etag/If-None-Match)與資料一起傳回給用戶端,用戶端将兩者都備份到緩存中 ,再次請求資料時,用戶端将上次備份的緩存辨別發送給服務端,服務端根據緩存辨別進行判斷, 如果傳回 304,則表示通知用戶端可以繼續使用緩存。否則會連帶着最新的資料一起傳回給用戶端。

強制緩存優先于對比緩存。 上面提到強制緩存使用的的兩個辨別:

Expires:Expires 的值為服務端傳回的到期時間,即下一次請求時,請求時間小于服務端返 回的到期時間,直接使用緩存資料。到期時間是服務端生成的,用戶端和服務端的時間可能有誤差。

Cache-Control:Expires 有個時間校驗的問題,所有 HTTP1.1 采用 Cache-Control 替代 Expires。

上面我們也也說到Cache-Control 的取值有以下幾種:

private: 用戶端可以緩存。 public: 用戶端和代理伺服器都可緩存。

max-age=xxx: 緩存的 内容将在 xxx 秒後失效

no-cache: 需要使用對比緩存來驗證緩存資料。

no-store: 所有内容都不會緩存,強制緩存,對比緩存都不會觸發。 我們再來看看對比緩存的兩個辨別:

Last-Modified/If-Modified-Since Last-Modified 表示資源上次修改的時間。 當用戶端發送第一次請求時,服務端傳回資源上次修改的時間:

Last-Modified: Tue, 12 Jan 2016 09:31:27 GMT 用戶端再次發送,會在 header 裡攜帶 If-Modified-Since。将上次服務端傳回的資源時間上 傳給服務端。

If-Modified-Since: Tue, 12 Jan 2016 09:31:27 GMT 服務端接收到用戶端發來的資源修改時間,與自己目前的資源修改時間進行對比,如果自己 的資源修改時間大于用戶端發來的資源修改時間,則說明資源做過修改, 則傳回 200 表示 需要重新請求資源,否則傳回 304 表示資源沒有被修改,可以繼續使用緩存。 上面是一種時間戳标記資源是否修改的方法,還有一種資源辨別碼 ETag 的方式來标記是否 修改,如果辨別碼發生改變,則說明資源已經被修改,ETag 優先級高于 Last-Modified。 Etag/If-None-Match ETag 是資源檔案的一種辨別碼,當用戶端發送第一次請求時,服務端會傳回目前資源的标 識碼: ETag: “5694c7ef-24dc” 用戶端再次發送,會在 header 裡攜帶上次服務端傳回的資源辨別碼: If-None-Match:“5694c7ef-24dc” 服務端接收到用戶端發來的資源辨別碼,則會與自己目前 的資源嗎進行比較,如果不同,則說明資源已經被修改,則傳回 200,如果相同則說明資源 沒有被修改,傳回 304,用戶端可以繼續使用緩存。

10.聊聊Http的缺點

HTTP的主要缺點其實還是不夠安全,主要有以下三點:

1.通信使用明文(不加密),内容可能會被竊聽。

2.不驗證通信方的身份,是以有可能遭遇僞裝。

3.無法證明封包的完整性,是以有可能已遭篡改。