文章持續更新,能夠微信搜一搜「golang小白成長記」第一時間閱讀,回覆【教程】獲golang免費視頻教程。本文已經收錄在GitHub https://github.com/xiaobaiTec... , 有大廠面試完整考點和成長路線,歡迎Star。
HTTP 全稱超⽂文本傳輸協議,也就是HyperText Transfer Protocol。
其中咱們常見的文本,圖片,視頻這些東西均可以用超文本進行表示,而我常看的貓片,也屬於超文本,因此你們不要再說我偷偷看貓片了,我只是在看超文本。HTTP只是定義了一套傳輸超文本的規則,只要符合了這一套規則,無論你是用iphone,仍是用老爺機,均可以實現貓片的傳輸。html
大概瞭解了HTTP後,給你們看看它在它們家族裏的地位。HTTP位於應用層,跟它相似的協議還有常見的FTP協議,常見的某影天堂的下載連接曾經常常是以FTP開頭的。nginx
有點抽象?不知道小白說的啥?那實操一下,用wireshark
抓包看一下貓片裏的請求報文和響應報文具體長什麼樣子吧git
GET /cmaskboss/164203142_30_1.enhance.webmask HTTP/1.1 Host: upos-sz-staticks3.bilivideo.com Connection: keep-alive User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Accept: */* Origin: https://www.bilibili.com Sec-Fetch-Site: cross-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://www.bilibili.com/ Accept-Encoding: identity Accept-Language: zh-CN,zh;q=0.9 Range: bytes=0-16
這上面第一行的GET 就是請求方法,/cmaskboss/164203142_30_1.enhance.webmask
則是 URL , 而HTTP/1.1
則是協議版本。接下來從Host
開始到最後一行Range
,都是Headers頭。程序員
HTTP/1.1 206 Partial Content Content-Type: application/octet-stream Content-Length: 17 Connection: keep-alive Server: Tengine ETag: "92086de1e6d1d4791fb950a0ac7e30ba" Date: Sat, 30 Jan 2021 09:31:31 GMT Last-Modified: Sun, 04 Oct 2020 01:54:28 GMT Expires: Mon, 01 Mar 2021 09:31:31 GMT Age: 1018695 Content-Range: bytes 0-16/353225 Accept-Ranges: bytes X-Application-Context: application x-kss-request-id: 75bcbfa8ab194e3c825e89c81a912692 x-kss-BucketOwner: MjAwMDAyMDEwNw== X-Info-StorageClass: - Content-MD5: kght4ebR1HkfuVCgrH4wug== X-Cache-Status: HIT from KS-CLOUD-JH-MP-01-03 X-Cache-Status: HIT from KS-CLOUD-TJ-UN-14-13 X-Cache-Status: HIT from KS-CLOUD-LF-UN-11-25 Access-Control-Allow-Origin: https://www.bilibili.com Access-Control-Allow-Headers: Origin,X-Requested-With,Content-Type,Accept,range X-Cdn-Request-ID: 7e2c783ca7d392624118593ec1dc66bc
相似請求報文,HTTP/1.1
是協議版本,206
是狀態碼,Partial Content
則是狀態描述符。接下來從Content-Type
開始到最後一行X-Cdn-Request-ID
都是Headers信息。github
其實上面的抓包信息,在瀏覽器裏按F12就能看到,之因此要用wireshark
可能只是裝X效果比較好吧。按下F12看到的響應數據就跟下圖展現的那樣。golang
URL 表明着是統一資源定位符(Uniform Resource Locator)。做用是爲了告訴使用者 某個資源在 Web 上的地址。這個資源能夠是一個 HTML 頁面,一個 CSS 文檔,一幅圖像或一個貓片等等。上面咱們請求貓片的URL就是 https://upos-sz-staticks3.bilivideo.com/cmaskboss/164203142_30_1.enhance.webmask
這裏面細分,又能夠分爲好幾個部分。web
表示該URL的協議部分爲http仍是https,會用//爲分隔符。上面的URL表示網頁用的是HTTPS協議,而上面提到的X影天堂用的則是ftp協議的下載連接。面試
域名是upos-sz-staticks3.bilivideo.com
,在發送請求前,會向DNS服務器解析IP,若是已經知道ip,還能夠跳過DNS解析那一步,直接把IP當作域名部分使用。shell
域名後面有些時候會帶有端口,和域名之間用:分隔,端口不是一個URL的必須的部分。當網址爲http://時,默認端口爲80json
當網址爲https://時,默認端口爲443,以上兩種均可以省略端口號。上面的URL其實省略了443端口號。
從域名的第一個/開始到最後一個/爲止,是虛擬目錄的部分。虛擬目錄也不是URL必須的部分,本例中的虛擬目錄是/cmaskboss/
從域名最後一個/開始到?爲止,是文件名部分;若是沒有?,則是從域名最後一個/開始到#爲止,是文件名部分;若是沒有?和#,那麼就從域名的最後一個/從開始到結束,都是文件名部分。本例中的文件名是164203142_30_1.enhance.webmask
,文件名也不是一個URL的必須部分。
其實一直有個誤解,不少人覺得URI是URL的子集,其實應該反過來。URL是URI的子集纔對。簡單解釋下。
假設"小白"(URI)是一種資源,而"在迪麗亦巴的懷裏"代表了一個位置。若是你想要找到(locate)小白,那麼你能夠到"在迪麗亦巴懷裏"找到小白,而"在迪麗亦巴懷裏的/小白"纔是咱們常說的URL。而"在迪麗亦巴懷裏的/小白"(URL)顯然是"小白"(URI)的子集,畢竟,"小白"還多是"在牛亦菲懷裏的/小白"(其餘URL)。
.jpg)
HTTP 定義了一組請求方法,以代表要對給定資源執行的操做。指示針對給定資源要執行的指望動做.。雖然他們也能夠是名詞,但這些請求方法有時被稱爲HTTP動詞.。每個請求方法都實現了不一樣的語義。
此次請求B站貓片的請求裏用的是GET,意味着獲取。但其實HTTP定義了多種請求方法,來知足各類需求。除了Get,還有幾個POST、HEAD、OPTIONS、PUT、DELETE、TRACE 和 CONNECT。
常見的各個請求方法的具體功能以下:
請求指定的頁面信息,並返回消息主體(body)+頭信息(header)。
HEAD和GET本質是同樣的,區別在於HEAD只返回頭信息(header),不返回消息主體(body)。你們不要覺得它沒用,它跟GET和POST同樣,在http/1.0的時候就存在了,實屬三元老之一了。主要用途
content-lenght
)。向服務器提交數據。這個方法用途普遍,幾乎目前全部的提交操做都是靠這個完成。POST跟GET最經常使用,但最大的區別在於,POST每次調用均可能會修改數據,是非冪等的,而GET相似於只讀,是冪等的。
這個方法比較少見。在HTTP規範中POST是非等冪的,屢次調用會產生不一樣的結果。好比:建立一個用戶,因爲網絡緣由或是其餘緣由多建立了幾回,那麼將會有多個用戶被建立。而PUT id/xiaobai 則會建立一個id爲 xiaobai 的用戶,屢次調用仍是會建立的結果是同樣的,因此PUT是等冪的。可是通常爲了不形成心智負擔,實戰中也會使用POST替代PUT。
刪除某一個資源。基本上這個也不多見,通常實戰中若是是刪除操做,也是使用POST來替代。
它用於獲取當前URL所支持的方法。若請求成功,則它會在HTTP響應頭部中帶上給各類「Allow」的頭,代表某個請求在對應的服務器中都支持哪一種請求方法。好比下圖:
這裏面須要關注的點有兩個
.jpg)
.jpg)
Options
堪稱是網絡協議中的老實人,就好像老實人剛談了個女友,每次牽手前都要問下人家 「我能夠牽你的手嗎?」, 「我能夠抱你嗎?」,獲得了答應後纔會下手。差點被這老實人氣質感動得留下了不爭氣的淚水。
在跨域(記住這個詞,待會解釋)的狀況下,瀏覽器發起複雜請求前會自動發起 options 請求。跨域共享標準規範要求,對那些可能對服務器數據產生反作用的 HTTP 請求方法(特別是 GET 之外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 options 方法發起一個預檢請求,從而獲知服務端是否容許該跨域請求。服務器確認容許以後,才發起實際的 HTTP 請求。
這裏提到了兩個關鍵詞:
某些請求不會觸發 CORS 預檢請求,這樣的請求通常稱爲"簡單請求",而會觸發預檢的請求則爲"複雜請求"。
簡單請求
GET、HEAD、POST
只有如下Headers
字段
Accept
Accept-Language
Content-Language
Content-Type
DPR/Downlink/Save-Data/Viewport-Width/Width
(這些不常見,放在一塊兒)Content-Type
只有如下三種
application/x-www-form-urlencoded
multipart/form-data
text/plain
複雜請求
因而可知,由於上述請求在獲取B站資源的請求Headers裏帶有 Access-Control-Request-Headers: range
, 而range
正好不在簡單請求的條件2中提到的Headers範圍裏,所以屬於複雜請求,因而觸發預檢options請求。
剛剛提到了一個詞叫跨域,那什麼是跨域呢?在瞭解跨域以前,首先要了解一個概念:同源。所謂同源是指,域名、協議、端口均相同。
不明白不要緊,舉個例子。
須要特別注意的是,localhost和127.0.0.1雖然都指向本機,但也不屬於同源。
而非同源之間網頁調用就是咱們所說的跨域。在瀏覽器同源策略限制下,向不一樣源發送XHR請求,瀏覽器認爲該請求不受信任,禁止請求,具體表現爲請求後不正常響應。
因而可知,複雜請求的條件其實很是容易知足,而一旦知足複雜請求的條件,則瀏覽器便會發送2次請求(一次預檢options,一次複雜請求),這一次options就一來一回(一個RTT),顯然會致使延遲和沒必要要的網絡資源浪費,高併發狀況下則可能爲服務器帶來嚴重的性能消耗。
.jpg)
每次複雜請求前都會調用一次options,這其實很是沒有必要。由於大部分時候相同的請求,短期內得到的結果是不會變的,是否能夠經過瀏覽器緩存省掉這一次查詢?
Access-Control-Max-Age
就是優化這個流程中使用的一個Header。它的做用是當你每次請求options
方法時,服務端返回調用支持的方法(Access-Control-Allow-Methods )和Headers(Access-Control-Allow-Headers)有哪些,同時告訴你,它在接下來 Access-Control-Max-Age
時間(單位是秒)裏都支持,則這段時間內,再也不須要使用options進行請求。特別注意的是,當Access-Control-Max-Age
的值爲-1時,表示禁用緩存,每一次請求都須要發送預檢請求,即用OPTIONS請求進行檢測。
HTTP Status Code則是常說的HTTP狀態碼。當用戶訪問一個網頁時,瀏覽器會向網頁所在服務器發出請求。服務器則會根據請求做出響應,而狀態碼則是響應的一部分,表明着本次請求的結果。全部狀態碼的第一個數字表明瞭響應的大概含義,組合上第二第三個數字則能夠表示更具體的緣由。若是請求失敗了,經過這個狀態碼,大概初步判斷出此次請求失敗的緣由。如下是五類狀態碼的含義。
能夠根據如下流程圖瞭解下各種狀態碼間的關係。
.jpg)
.jpg)
這是最多見的狀態碼。表明請求已成功,數據也正常返回。而B站貓片裏雖然響應成功了,但卻不是200,而是206,是爲何呢,接下去繼續看看。
這個狀態碼在上面B站請求的響應結果。服務器已經成功處理了部分 GET 請求。相似於B站看視頻或者迅雷這類的 HTTP下載工具都是使用此類響應實現斷點續傳或者將一個大文檔分解爲多個下載段同時下載。
內部重定向。重定向的意思是,當你輸入一個網址的時候,瀏覽器會自動幫你跳轉到另一個網址上。好比,當你在瀏覽器輸入框輸入http://www.baidu.com/
時。因爲使用http並不安全,百度會自動幫你跳轉到它對應的https網頁上。而此時,須要重定向的地址,會經過Response Headers
的Location
返回
請求失敗,請求所但願獲得的資源未被在服務器上發現。出現這個錯誤的最有可能的緣由是服務器端沒有這個頁面,或者是Request Method與註冊URL的Method不一致,好比我有一個URL在服務端註冊的Request Method 爲 POST,但調用的時候卻錯誤用了GET,則也會出現404錯誤。
網絡請求過程當中,因爲服務端處理時間過長,客戶端超時。通常常見於,後端服務器處理時間過長,而客戶端也設置了一個超時等待時間,客戶端等得「不耐煩」了,主動關掉鏈接時報出。
服務器方面沒法給於正常的響應。通常常見於服務器崩潰後,nginx 沒法正常收到服務端的響應,給客戶端返回502狀態碼。
.jpg)
網絡請求過程當中,因爲服務端處理時間過長,網關超時。通常常見於,後端服務器邏輯處理時間過長,甚至長於 nginx設置的最長等待時間時報錯。它跟 499 狀態碼很是像,區別在於499 表示的是客戶端超時,504是網關超時。若是是499超時,能夠考慮修改客戶端的代碼調整超時時間,若是是504,則考慮調整nginx的超時配置。
.jpg)
Content-Length
是HTTP的消息長度, 用十進制數字表示。Content-Length
首部指出報文中消息的當前實際字節大小。若是消息文本進行了gzip壓縮的話, Content-Length
指的就是壓縮後的大小而不是原始大小。
正常狀況下Content-Length
是不須要手動去設置的,大部分語言的網絡庫都會自動封裝好,可是若是在一些特殊狀況下,出現Content-Length
與實際要發送的消息大小不一致,就會出現一些問題。
若是Content-Length
< 實際長度
下面啓動一個HTTP服務器,全部語言都同樣,示例裏使用了golang。
package main import ( "fmt" "io/ioutil" "log" "net/http" ) // w表示response對象,返回給客戶端的內容都在對象裏處理 // r表示客戶端請求對象,包含了請求頭,請求參數等等 func index(w http.ResponseWriter, r *http.Request) { b, _ := ioutil.ReadAll(r.Body) fmt.Printf("request body=%#v, content_length=%v \nheaders=%v",string(b), r.ContentLength, r.Header) // 往w裏寫入內容,就會在瀏覽器裏輸出 fmt.Fprintf(w, string(b)) } func main() { // 設置路由,若是訪問/,則調用index方法 http.HandleFunc("/", index) // 啓動web服務,監聽9090端口 err := http.ListenAndServe(":9999", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
在控制檯輸入
$ $ curl -L -X POST 'http://127.0.0.1:9999' -H 'Content-Type: application/json' -H 'Content-Length: 5' -d '1234567' | jq % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 12 100 5 100 7 828 1160 --:--:-- --:--:-- --:--:-- 1400 12345
輸入的body是 1234567
,共7個數字,可是輸入的 Content-Length
爲 5。到了服務器那,收到了 12345
,共5個數字,數量上跟輸入的Content-Length
一致。 因而可知當Content-Length
< 實際長度, 消息會被截斷。
若是Content-Length
> 實際長度
仍是上面的服務端代碼,可是控制檯輸入如下命令
$ curl -L -X POST 'http://127.0.0.1:9999' -H 'Content-Type: application/json' -H 'Content-Length: 100' -d '1234567' | jq % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 7 0 0 0 7 0 0 --:--:-- 0:01:19 --:--:-- 0
此次狀況不太同樣,會發現請求一直阻塞沒有返回。這是由於輸入的body是 1234567
,共7個數字,可是輸入的 Content-Length
爲 100。也就是服務端一直認爲此次的body長度爲100,可是目前只收到了部分消息(長度爲7),剩餘的長度爲93的消息因爲各類緣由還在路上,所以選擇傻傻等待剩下的消息,就形成了上面提到的阻塞。
視頻播放須要支持用戶調整播放進度,支持讓用戶選擇直接跳到中間部分開始播放。爲了實現這個功能,須要經過HTTP Range Requests 協議用於指定須要獲取視頻片斷。而 Request Header裏的range頭則是用於指定要請求文件的起始和結束位置。
當咱們在 html 中放一個 video 標籤,瀏覽器會直接發起一個 Range: bytes=0-
的請求,向服務器請求從開始到結尾的完整文件
Content-Range: 開始字節位置-結束字節位置/文件大小(byte)
。表示請求響應完成以後當即關閉鏈接,這是HTTP/1.0請求的默認值。每次請求都通過「建立tcp鏈接 -> 請求資源 -> 響應資源 -> 釋放鏈接」這樣的過程
表示鏈接不當即關閉,能夠繼續響應下一個請求。HTTP/1.1的請求默認使用一個持久鏈接。能夠作到只創建一次鏈接,屢次資源請求都複用該鏈接,完成後關閉。流程上是 創建tcp鏈接 -> 請求資源 -> 響應資源 -> ... (保持鏈接)... -> 第n次請求資源 -> 第n次響應資源 -> 釋放鏈接。
在http1.1中Request Header和Reponse Header中都有可能出現一個Connection: keep-alive 頭信息。Request Header裏的Connection: keep-alive 頭是爲了告訴服務端,客戶端想要以長鏈接形式進行通訊。而Response Header裏的Connection: keep-alive 頭是服務端告訴客戶端,個人服務器支持以長鏈接的方式進行通訊。若是不能使用長鏈接,會返回 Connection: close ,至關於告訴客戶端「我不支持長鏈接,你死了這條心,老老實實用短鏈接吧」 。
咱們知道 HTTP 創建在 TCP 傳輸層協議之上,而 TCP 的創建須要三次握手,關閉須要四次揮手,這些步驟都須要時間,帶給 HTTP 的就是請求響應時延。若是使用短鏈接,那麼每次數據傳輸都須要經歷一次上面提到的幾個步驟,若是能只鏈接一次,保持住這個鏈接不斷開,期間通訊就能夠省下創建鏈接和斷開鏈接的過程,對於提高HTTP性能有很大的幫助。
Cookie 通常有兩個做用。
識別用戶身份。
持久化用戶信息。
Referrer 是HTTP請求header的報文頭,用於指明當前流量的來源參考頁面,常被用於分析用戶來源等信息。經過這個信息,咱們能夠知道訪客是怎麼來到當前頁面的。好比在上面的請求截圖裏,能夠看出我是使用https://www.bilibili.com/
訪問的視頻資源。
爲何要這麼麻煩呢?由於有些網站一些用戶敏感信息,好比 sessionid 或是 token 放在地址欄裏,若是當作Referrer字段所有傳遞的話,那第三方網站就會拿到這些信息,會有必定的安全隱患。因此就有了 Referrer Policy,用於過濾 Referrer 報頭內容。
好比在上面的請求截圖裏,能夠看出我是使用strict-origin-when-cross-origin
策略,含義是跨域時將當前頁面URL過濾掉參數及路徑部分,僅將協議、域名和端口(若是有的話)看成 Referrer。不然 Referrer 仍是傳遞當前頁的全路徑。同時當發生降級(好比從 https:// 跳轉到 http:// )時,不傳遞 Referrer 報頭。
cache-control,用於控制瀏覽器緩存。簡而言之,當某人訪問網站時,其瀏覽器將在本地保存某些資源,例如圖像和網站數據。當該用戶從新訪問同一網站時,緩存控制設置的規則會肯定該用戶是否從本地緩存中加載這些資源,或者瀏覽器是否必須向服務器發送新資源的請求。
瀏覽器緩存是指瀏覽器本地保存網站資源,以便沒必要再次經過網絡從服務器獲取它們。例如,「貓貓網」的背景圖像能夠保存到本地緩存中,這樣在用戶第二次訪問該頁面時,該圖像將從用戶的本地文件加載,剩下網絡獲取資源的時間,頁面加載速度就會更快。
可是瀏覽器也不會永遠把這些網站資源放在本地,不然本地磁盤就會炸,因此會限定保存資源的時間,這叫生存時間(TTL)。若是 TTL 過時後用戶請求緩存的資源,瀏覽器必須再次經過網絡與服務器創建鏈接並從新下載這個資源。
從B站截圖裏能夠看出,使用的緩存控制指令是cache-control: no-cache
。它表示,只有先檢查資源沒有更新版本後,纔可以使用所請求資源的緩存版本。那麼問題來了,怎麼判斷資源是否有更新版本呢?這就須要 ETag
。
Etag是 Entity tag的縮寫,是服務端的一個資源版本的令牌標識。在 HTTP 響應頭中將其傳送到客戶端。每當資源更新時,此令牌會源站服務器上更改。
ETag: "095933fff2323351d3b495f2f879616f1762f752"
。當瀏覽器再次請求這個資源的時候,瀏覽器會將If-None-Match: "095933fff2323351d3b495f2f879616f1762f752"
傳輸給服務端,服務端拿到該ETAG,對比資源是否發生變化。
果真B站是個充滿學習氛圍的地方,看個貓片都能學到這麼多硬核知識。接下來我打算去舞蹈區看看有沒有適合大家的知識點。
我是小白,有空?一塊兒在知識的海洋裏嗆水啊,懂我意思?
- [1] 計算機網絡自動向下
- [2] 極客時間-趣談網絡協議
- [3] 極客時間-透視HTTP
- [4] 圖解HTTP
- [5] 漫畫形象-小肥柴