- 五年前,我來北京參加面試, 一個面試官問我,你是做什么的,我說PHP全棧(年輕無畏,哈哈),然后面試官說,一個http的header都包含哪些信息你知道嗎?然后我就慫了。。。。
- 那么今天,我們就來聊一聊http
HTTP的發(fā)展歷史
- HTTP,全稱Hyper Text Transfer Protocol,即超文本傳輸協(xié)議,是一個簡單的請求-響應協(xié)議,它通常運行在TCP之上。
- HTTP目前一共經(jīng)歷了HTTP 0.9,HTTP 1.0,HTTP 1.1,HTTP 2.0,那么我們分別來看看每個版本的HTTP的功能和發(fā)生的變化
HTTP 0.9
HTTP 0.9是第一個版本的HTTP協(xié)議,已過時。它只允許客戶端發(fā)送GET這一種請求,而想我們常用的POST PUT DELETE 是不支持的,而且由于不支持請求頭,所以我們只能獲取一些純文本,如果你想獲取一個圖片,不好意思,不支持。
從HTTP 0.9開始,HTTP就是無狀態(tài)的,每個事務獨立進行處理,事務結束時就釋放這個連接。一次HTTP 0.9的傳輸首先要建立一個由客戶端到Web服務器的TCP連接,由客戶端發(fā)起一個請求,然后由Web服務器返回頁面內容,然后連接會關閉。如果請求的頁面不存在,也不會返回任何錯誤碼。
HTTP 1.0
HTTP 1.0是HTTP協(xié)議的第二個版本,第一個在通訊中指定版本號的HTTP協(xié)議版本,至今仍被廣泛采用。相對于HTTP 0.9 增加了如下主要特性:
- 請求與響應支持頭域
- 響應對象以一個響應狀態(tài)行開始
- 響應對象不只限于超文本,還可以傳輸圖像、音頻、視頻等二進制文件。
- 開始支持客戶端通過POST方法向Web服務器提交數(shù)據(jù),支持GET、HEAD、POST方法
- 開始支持cache,就是當客戶端在規(guī)定時間內訪問同一網(wǎng)站,直接訪問cache即可。
- 支持返回狀態(tài)碼,方便了錯誤排查(504 502 404 403 302 301 等等),我們后面會開個小節(jié)去介紹
- 新增功能還包括狀態(tài)碼(status code)、多字符集支持、多部分發(fā)送(multi-part type)、權限(authorization)、緩存(cache)、內容編碼(content encoding)等。
- 每次 TCP 連接只能發(fā)送一個請求,當服務器響應后就會關閉這次連接,下一個請求需要再次建立 TCP 連接。 TCP 連接的建立成本很高,因為需要客戶端和服務器三次握手,并且開始時發(fā)送速率較慢(slow start)。為了解決這個問題,有些瀏覽器在請求時,即在請求頭部加上 Connection 字段:
在這里插入圖片描述
比如,我們請求一個html頁面,里面有一個css文件和一個js文件,那么當我們訪問這個頁面的時候,就會建立三次tcp連接,這種形式就會造成性能上的缺陷,如果我們想要建立長連接,就要設置一個非標準的connection字段Connection:keep-alive
HTTP1.1
- HTTP1.1開始,默認支持長連接
Connection: keep-alive
,即在一個TCP 連接上我們可以傳送多個http請求和響應,減少了建立tcp連接的次數(shù),提高了http傳輸?shù)男阅?br>在這里插入圖片描述 - 加入了管道機制
在同一個 TCP 連接里,允許多個請求同時發(fā)送,增加了并發(fā)性,進一步改善了 HTTP 協(xié)議的效率。
舉例來說,客戶端需要請求兩個資源。以前的做法是,在同一個 TCP 連接里面,先發(fā)送 A 請求,然后等待服務器做出回應,收到后再發(fā)出 B 請求。
管道機制則是允許瀏覽器同時發(fā)出 A 請求和 B 請求,但是服務器還是按照順序,先回應 A 請求,完成后再回應 B 請求。 - HTTP 1.1 支持文件斷點續(xù)傳,RANGE:bytes,HTTP 1.0 每次傳送文件都是從文件頭開始,即 0 字節(jié)處開始。RANGE:bytes=XXXX 表示要求服務器從文件 XXXX 字節(jié)處開始傳送,斷點續(xù)傳。即返回碼是 206(Partial Content)
- 引入了更多的緩存控制策略,如If-Unmodified-Since, If-Match, If-None-Match等緩存頭來控制緩存策略
- 引入host,實現(xiàn)了在一臺WEB服務器上可以在同一個IP地址和端口號上使用不同的主機名來創(chuàng)建多個虛擬WEB站點
- 添加了其他的請求方法:put、delete、options
HTTP2.0
HTTP2.0在相比之前版本,性能上有很大的提升
-
多路復用
HTTP 2.0 復用 TCP 連接,在一個連接里,客戶端和瀏覽器都可以同時發(fā)送多個請求或回應,而且不用按照順序一一對應,這樣就避免了"隊頭堵塞"(HTTP 2.0 使用了多路復用的技術,做到同一個連接并發(fā)處理多個請求,而且并發(fā)請求的數(shù)量比 HTTP 1.1大了好幾個數(shù)量級)。
舉例來說,在一個 TCP 連接里面,服務器同時收到了 A 請求和 B 請求,于是先回應 A 請求,結果發(fā)現(xiàn)處理過程非常耗時,于是就發(fā)送 A 請求已經(jīng)處理好的部分, 接著回應 B 請求,完成后,再發(fā)送 A 請求剩下的部分。
在這里插入圖片描述
二進制分幀
HTTP 1.1 版的頭信息肯定是文本(ASCII 編碼),數(shù)據(jù)體可以是文本,也可以是二進制。
HTTP 2.0 則是一個徹底的二進制協(xié)議,頭信息和數(shù)據(jù)體都是二進制,并且統(tǒng)稱為"幀"(frame):頭信息幀和數(shù)據(jù)幀。-
首部壓縮
HTTP 協(xié)議不帶有狀態(tài),每次請求都必須附上所有信息。所以,請求的很多字段都是重復的,比如 Cookie 和 User Agent,一模一樣的內容,每次請求都必須附帶,這會浪費很多帶寬,也影響速度。
HTTP 2.0 對這一點做了優(yōu)化,引入了頭信息壓縮機制(header compression)。一方面,頭信息使用 gzip 或c ompress 壓縮后再發(fā)送;另一方面,客戶端和服務器同時維護一張頭信息表,所有字段都會存入這個表,生成一個索引號,以后就不發(fā)送同樣字段了,只發(fā)送索引號,這樣就提高速度了。
在這里插入圖片描述 -
服務器推送
HTTP 2.0 允許服務器未經(jīng)請求,主動向客戶端發(fā)送資源,這叫做服務器推送(server push)。意思是說,當我們對支持 HTTP 2.0 的 web server 請求數(shù)據(jù)的時候,服務器會順便把一些客戶端需要的資源一起推送到客戶端,免得客戶端再次創(chuàng)建連接發(fā)送請求到服務器端獲取。這種方式非常合適加載靜態(tài)資源。服務器端推送的這些資源其實存在客戶端的某處地方,客戶端直接從本地加載這些資源就可以了,不用走網(wǎng)絡,速度自然是快很多的。
在這里插入圖片描述
HTTP請求頭和響應頭的這些知識
- 我以下面我請求的這個地址為栗子
Genneral
Request URL: https://m.acurd.com/blog-21/yqa242q620.html #請求地址
Request Method: GET #請求方式
Status Code: 200 OK #相應狀態(tài)
Remote Address: 122.22.22.22:443 #遠程服務器的地址 和端口號 http 訪問是80 htts是443
Referrer Policy: strict-origin-when-cross-origin #Referrer-Policy的作用就是為了控制請求頭中referrer的內容,目前是一個候選標準,可以控制referer的顯示條件 顯示 不顯示 跨域顯示等等
Request Headers
GET /blog-21/yqa242q620.html HTTP/1.1 # 請求地址 http協(xié)議版本號
Host: m.acurd.com #服務器域名
Connection: keep-alive # 該瀏覽器想要優(yōu)先使用的連接類型
Cache-Control: max-age=0 # 用來指定在這次的請求/響應鏈中的所有緩存機制
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-
Referer: https://m.acurd.com/blog-21.html #訪問來源
Response Headers
HTTP/1.1 200 OK #http協(xié)議 響應碼
Server: nginx # 服務器
Date: Mon, 10 Jan 2022 09:15:17 GMT #相應時間
Content-Type: text/html; charset=utf-8 #相應類型和字符類型
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
X-Powered-By: PHP/7.2.24 #解釋器
Expires: Thu, 19 Nov 1981 08:52:00 GMT #緩存過期時間
Cache-Control: no-store, no-cache, must-revalidate #緩存機制 比如不需要Nginx緩存的,我們就設置成no-cache
- 其實大概來講 就是幾個,從哪來,到哪去,要什么,哪種方式傳輸 ,使用什么瀏覽器,緩存機制,緩存時間,字符類型
- 協(xié)商緩存
協(xié)商緩存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】這兩對請求頭響應頭來管理的
Last-Modified 表示本地文件最后修改日期,瀏覽器會在request header加上If-Modified-Since(上次返回的Last-Modified的值),詢問服務器在該日期后資源是否有更新,有更新的話就會將新的資源發(fā)送回來
Etag就像一個指紋,資源變化都會導致ETag變化,跟最后修改時間沒有關系,ETag可以保證每一個資源是唯一的
If-None-Match的header會將上次返回的Etag發(fā)送給服務器,詢問該資源的Etag是否有更新,有變動就會發(fā)送新的資源回來
而強制緩存不需要發(fā)送請求到服務端,根據(jù)請求頭expires和cache-control判斷是否命中強緩存
比如es的遠程詞庫我們就需要通過配置 Last-Modified和ETag來確定是否要重新獲取遠程詞庫
關于http狀態(tài)碼的講解
- 200 (成功) 服務器已成功處理了請求。 通常,這表示服務器提供了請求的網(wǎng)頁。
- 301 (永久移動) 請求的網(wǎng)頁已永久移動到新位置。 服務器返回此響應(對 GET 或 HEAD 請求的響應)時,會自動將請求者轉到新位置。
- 302 (臨時移動) 服務器目前從不同位置的網(wǎng)頁響應請求,但請求者應繼續(xù)使用原有位置來進行以后的請求。
301和302的區(qū)別,301: 舊地址A的資源不可訪問了(永久移除), 重定向到網(wǎng)址B,搜索引擎會抓取網(wǎng)址B的內容,同時將網(wǎng)址保存為B網(wǎng)址。 302: 舊地址A的資源仍可訪問,這個重定向只是臨時從舊地址A跳轉到B地址,這時搜索引擎會抓取B網(wǎng)址內容,但是會將網(wǎng)址保存為A的。
簡單來說,301的話搜索引擎認為地址a廢棄了,只抓取b的內容,存的網(wǎng)址也是b,302是說a地址還可以提供服務,只是暫時從b地址d - 403 (禁止) 服務器拒絕請求。
- 404 (未找到) 服務器找不到請求的網(wǎng)頁。
- 500 (服務器內部錯誤) 服務器遇到錯誤,無法完成請求。
比如我的PHP文件中調用了一個不存在的類
在這里插入圖片描述
調試狀態(tài)下,如果我們加了ini_set("display_errors",true);
nginx 就會返回200,并暴露錯誤
502 (錯誤網(wǎng)關) 服務器作為網(wǎng)關或代理,從上游服務器收到無效響應。
- nginx+php 出現(xiàn) 502 bad gateway,一般這都不是 nginx 的問題,而是由于 fastcgi 或者 php 的問題導致的,
- php.ini 的 memory_limit 過小
- php-fpm.conf 中 max_children 或者 max_requests 設置不合理(設置過小會因為沒有足夠的 cgi 進程處理請求,設置過大會出現(xiàn)一會兒有響應正常,一會兒等很久才有響應的情況,一般情況下 children 按 照內存計算,比如說 1G 設置 64 ,2G 設置 128。這個根據(jù)實際情況自行調整。另外查看當前的 PHP FastCGI 進程數(shù)是否夠用的命令為:
netstat -anpo | grep "php-cgi" | wc -l
如果實際使用的 FastCGI進程數(shù) 接近預設的 FastCGI進程數(shù),那么,說明FastCGI進程數(shù)不夠用,需要增大。) - php 程序執(zhí)行時間過長而超時 檢查 nginx 和 fastcgi 中各種 timeout 設置。(nginx 中的 fastcgi_connect_timeout 300; 、fastcgi_send_timeout 300; 、fastcgi_read_timeout 300; 、keepalive_timeout php-fpm 中的 request_terminate_timeout,php.ini 中的 max_execution_time)
-
php-fpm 有一個參數(shù) max_requests ,該參數(shù)指明了每個 children 最多處理多少個請求后便會被關閉。在大量處理請求下,如果該值設置過小會導致 children 頻繁的自殺和建立而浪費 大量時間,若所有的 children 差不多都在這個時候自殺,則重建前將沒有 children 響應請求,于是出現(xiàn) 502 。可以將該值設置大一些或者是 0 [無限]。
簡單來說,php-cgi 進程數(shù)不夠用、 php 執(zhí)行時間長、或者是 php-cgi 進程死掉,都會出現(xiàn) 502 錯誤。我們來演示一下
在這里插入圖片描述
504 (網(wǎng)關超時) 服務器作為網(wǎng)關或代理,但是沒有及時從上游服務器收到請求。
- nginx訪問出現(xiàn)504 Gateway Time-out,一般是由于程序執(zhí)行時間過長導致響應超時,例如程序需要執(zhí)行90秒,而nginx最大響應等待時間為30秒,這樣就會出現(xiàn)超時。
- 可能原因
1.程序在處理大量數(shù)據(jù),導致等待超時。
2.程序中調用外部請求,而外部請求響應超時。
3.連接數(shù)據(jù)庫失敗而沒有停止,死循環(huán)重新連。
出現(xiàn)這種情況,我們可以先優(yōu)化程序,縮短執(zhí)行時間。另一方面,可以調大nginx超時限制的參數(shù),使程序可以正常執(zhí)行。
- 解決方案
- nginx.conf中,設置以下幾個參數(shù),增加超時時間
fastcgi_connect_timeout
fastcgi連接超時時間,默認60秒
fastcgi_send_timeout
nginx 進程向 fastcgi 進程發(fā)送請求過程的超時時間,默認值60秒
fastcgi_read_timeout
fastcgi 進程向 nginx 進程發(fā)送輸出過程的超時時間,默認值60秒 - php.ini的配置
max_execution_time
設置單個請求的超時時間
php程序中可加入set_time_limit(seconds)設置最長執(zhí)行時間
例如 set_time_limit(0) 表示不超時。
-
我們通過修改nginx的超時設置來演示一下504的情況
在這里插入圖片描述
CDN
CDN (全稱 Content Delivery Network),即內容分發(fā)網(wǎng)絡,構建在現(xiàn)有網(wǎng)絡基礎之上的智能虛擬網(wǎng)絡,依靠部署在各地的邊緣服務器,通過中心平臺的負載均衡、內容分發(fā)、調度等功能模塊,使用戶就近獲取所需內容,降低網(wǎng)絡擁塞,提高用戶訪問響應速度和命中率。CDN 的關鍵技術主要有內容存儲和分發(fā)技術
通俗來講,CDN 就像連鎖店,當我們想吃沙縣小吃的時候,我們不會真的跑到沙縣去吃,而是附近就可以找到沙縣小吃,而且全國的沙縣小吃菜單都一樣,每個沙縣小吃就是一個邊緣節(jié)點,那么我們怎么找到離我最近的沙縣小吃呢,這個時候就用到了CNAME(配置過網(wǎng)站的同學都見過)和負載均衡系統(tǒng),CNAME 就像你網(wǎng)站的別名,負載均衡系統(tǒng)會根據(jù)用戶的IP 找到最近的邊緣節(jié)點和運營商網(wǎng)絡,并根據(jù)節(jié)點的負載情況和相應性能,分發(fā)到相應的節(jié)點
DNS
DNS(Domain Names System),域名系統(tǒng),是互聯(lián)網(wǎng)一項服務,是進行域名和與之相對應的 IP 地址進行轉換的服務器,簡單來講,DNS相當于一個翻譯官,負責將域名翻譯成ip地址
- 計算機中DNS的記錄也分成了兩種緩存方式:
瀏覽器緩存:瀏覽器在獲取網(wǎng)站域名的實際 IP 地址后會對其進行緩存,減少網(wǎng)絡請求的損耗
操作系統(tǒng)緩存:操作系統(tǒng)的緩存其實是用戶自己配置的 hosts 文件
查詢過程
- 首先搜索瀏覽器的 DNS 緩存,緩存中維護一張域名與 IP 地址的對應表,
- 沒有命中則繼續(xù)搜索操作系統(tǒng)的 DNS 緩存
- 若仍然沒有命中,則操作系統(tǒng)將域名發(fā)送至本地域名服務器,本地域名服務器采用遞歸查詢自己的 DNS 緩存,查找成功則返回結果
- 若本地域名服務器的 DNS 緩存沒有命中,則本地域名服務器向上級域名服務器進行迭代查詢
- 本地域名服務器將得到的 IP 地址返回給操作系統(tǒng),同時自己將 IP 地址緩存起來
- 操作系統(tǒng)將 IP 地址返回給瀏覽器,同時自己也將 IP 地址緩存起
-
至此,瀏覽器就得到了域名對應的 IP 地址,并將 IP 地址緩存起
在這里插入圖片描述