- 五年前,我來北京參加面試孝常, 一個面試官問我旗们,你是做什么的,我說PHP全棧(年輕無畏构灸,哈哈)上渴,然后面試官說,一個http的header都包含哪些信息你知道嗎喜颁?然后我就慫了稠氮。。半开。隔披。
- 那么今天,我們就來聊一聊http
HTTP的發(fā)展歷史
- HTTP寂拆,全稱Hyper Text Transfer Protocol奢米,即超文本傳輸協(xié)議,是一個簡單的請求-響應(yīng)協(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)的屋摇,每個事務(wù)獨立進行處理揩魂,事務(wù)結(jié)束時就釋放這個連接。一次HTTP 0.9的傳輸首先要建立一個由客戶端到Web服務(wù)器的TCP連接炮温,由客戶端發(fā)起一個請求火脉,然后由Web服務(wù)器返回頁面內(nèi)容,然后連接會關(guān)閉柒啤。如果請求的頁面不存在倦挂,也不會返回任何錯誤碼。
HTTP 1.0
HTTP 1.0是HTTP協(xié)議的第二個版本担巩,第一個在通訊中指定版本號的HTTP協(xié)議版本方援,至今仍被廣泛采用。相對于HTTP 0.9 增加了如下主要特性:
- 請求與響應(yīng)支持頭域
- 響應(yīng)對象以一個響應(yīng)狀態(tài)行開始
- 響應(yīng)對象不只限于超文本兵睛,還可以傳輸圖像肯骇、音頻、視頻等二進制文件祖很。
- 開始支持客戶端通過POST方法向Web服務(wù)器提交數(shù)據(jù)笛丙,支持GET、HEAD假颇、POST方法
- 開始支持cache胚鸯,就是當客戶端在規(guī)定時間內(nèi)訪問同一網(wǎng)站,直接訪問cache即可笨鸡。
- 支持返回狀態(tài)碼姜钳,方便了錯誤排查(504 502 404 403 302 301 等等),我們后面會開個小節(jié)去介紹
- 新增功能還包括狀態(tài)碼(status code)形耗、多字符集支持哥桥、多部分發(fā)送(multi-part type)、權(quán)限(authorization)激涤、緩存(cache)拟糕、內(nèi)容編碼(content encoding)等。
- 每次 TCP 連接只能發(fā)送一個請求,當服務(wù)器響應(yīng)后就會關(guān)閉這次連接送滞,下一個請求需要再次建立 TCP 連接侠草。 TCP 連接的建立成本很高,因為需要客戶端和服務(wù)器三次握手犁嗅,并且開始時發(fā)送速率較慢(slow start)边涕。為了解決這個問題,有些瀏覽器在請求時褂微,即在請求頭部加上 Connection 字段:
在這里插入圖片描述
比如功蜓,我們請求一個html頁面,里面有一個css文件和一個js文件蕊梧,那么當我們訪問這個頁面的時候霞赫,就會建立三次tcp連接腮介,這種形式就會造成性能上的缺陷肥矢,如果我們想要建立長連接,就要設(shè)置一個非標準的connection字段Connection:keep-alive
HTTP1.1
- HTTP1.1開始叠洗,默認支持長連接
Connection: keep-alive
甘改,即在一個TCP 連接上我們可以傳送多個http請求和響應(yīng),減少了建立tcp連接的次數(shù)灭抑,提高了http傳輸?shù)男阅?br>在這里插入圖片描述 - 加入了管道機制
在同一個 TCP 連接里十艾,允許多個請求同時發(fā)送,增加了并發(fā)性腾节,進一步改善了 HTTP 協(xié)議的效率忘嫉。
舉例來說,客戶端需要請求兩個資源案腺。以前的做法是庆冕,在同一個 TCP 連接里面,先發(fā)送 A 請求劈榨,然后等待服務(wù)器做出回應(yīng)访递,收到后再發(fā)出 B 請求。
管道機制則是允許瀏覽器同時發(fā)出 A 請求和 B 請求同辣,但是服務(wù)器還是按照順序拷姿,先回應(yīng) A 請求,完成后再回應(yīng) B 請求旱函。 - HTTP 1.1 支持文件斷點續(xù)傳响巢,RANGE:bytes,HTTP 1.0 每次傳送文件都是從文件頭開始棒妨,即 0 字節(jié)處開始踪古。RANGE:bytes=XXXX 表示要求服務(wù)器從文件 XXXX 字節(jié)處開始傳送,斷點續(xù)傳。即返回碼是 206(Partial Content)
- 引入了更多的緩存控制策略灾炭,如If-Unmodified-Since, If-Match, If-None-Match等緩存頭來控制緩存策略
- 引入host茎芋,實現(xiàn)了在一臺WEB服務(wù)器上可以在同一個IP地址和端口號上使用不同的主機名來創(chuàng)建多個虛擬WEB站點
- 添加了其他的請求方法:put、delete蜈出、options
HTTP2.0
HTTP2.0在相比之前版本田弥,性能上有很大的提升
-
多路復(fù)用
HTTP 2.0 復(fù)用 TCP 連接,在一個連接里铡原,客戶端和瀏覽器都可以同時發(fā)送多個請求或回應(yīng)偷厦,而且不用按照順序一一對應(yīng),這樣就避免了"隊頭堵塞"(HTTP 2.0 使用了多路復(fù)用的技術(shù)燕刻,做到同一個連接并發(fā)處理多個請求只泼,而且并發(fā)請求的數(shù)量比 HTTP 1.1大了好幾個數(shù)量級)。
舉例來說卵洗,在一個 TCP 連接里面请唱,服務(wù)器同時收到了 A 請求和 B 請求,于是先回應(yīng) A 請求过蹂,結(jié)果發(fā)現(xiàn)處理過程非常耗時十绑,于是就發(fā)送 A 請求已經(jīng)處理好的部分, 接著回應(yī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)潜的,每次請求都必須附上所有信息骚揍。所以,請求的很多字段都是重復(fù)的啰挪,比如 Cookie 和 User Agent信不,一模一樣的內(nèi)容,每次請求都必須附帶亡呵,這會浪費很多帶寬抽活,也影響速度。
HTTP 2.0 對這一點做了優(yōu)化锰什,引入了頭信息壓縮機制(header compression)下硕。一方面丁逝,頭信息使用 gzip 或c ompress 壓縮后再發(fā)送;另一方面梭姓,客戶端和服務(wù)器同時維護一張頭信息表霜幼,所有字段都會存入這個表,生成一個索引號誉尖,以后就不發(fā)送同樣字段了罪既,只發(fā)送索引號,這樣就提高速度了铡恕。
在這里插入圖片描述 -
服務(wù)器推送
HTTP 2.0 允許服務(wù)器未經(jīng)請求琢感,主動向客戶端發(fā)送資源,這叫做服務(wù)器推送(server push)探熔。意思是說驹针,當我們對支持 HTTP 2.0 的 web server 請求數(shù)據(jù)的時候,服務(wù)器會順便把一些客戶端需要的資源一起推送到客戶端诀艰,免得客戶端再次創(chuàng)建連接發(fā)送請求到服務(wù)器端獲取柬甥。這種方式非常合適加載靜態(tài)資源。服務(wù)器端推送的這些資源其實存在客戶端的某處地方涡驮,客戶端直接從本地加載這些資源就可以了暗甥,不用走網(wǎng)絡(luò),速度自然是快很多的捉捅。
在這里插入圖片描述
HTTP請求頭和響應(yīng)頭的這些知識
- 我以下面我請求的這個地址為栗子
Genneral
Request URL: https://m.acurd.com/blog-21/yqa242q620.html #請求地址
Request Method: GET #請求方式
Status Code: 200 OK #相應(yīng)狀態(tài)
Remote Address: 122.22.22.22:443 #遠程服務(wù)器的地址 和端口號 http 訪問是80 htts是443
Referrer Policy: strict-origin-when-cross-origin #Referrer-Policy的作用就是為了控制請求頭中referrer的內(nèi)容,目前是一個候選標準虽风,可以控制referer的顯示條件 顯示 不顯示 跨域顯示等等
Request Headers
GET /blog-21/yqa242q620.html HTTP/1.1 # 請求地址 http協(xié)議版本號
Host: m.acurd.com #服務(wù)器域名
Connection: keep-alive # 該瀏覽器想要優(yōu)先使用的連接類型
Cache-Control: max-age=0 # 用來指定在這次的請求/響應(yīng)鏈中的所有緩存機制
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é)議 響應(yīng)碼
Server: nginx # 服務(wù)器
Date: Mon, 10 Jan 2022 09:15:17 GMT #相應(yīng)時間
Content-Type: text/html; charset=utf-8 #相應(yīng)類型和字符類型
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緩存的棒口,我們就設(shè)置成no-cache
- 其實大概來講 就是幾個,從哪來辜膝,到哪去无牵,要什么,哪種方式傳輸 厂抖,使用什么瀏覽器茎毁,緩存機制,緩存時間忱辅,字符類型
- 協(xié)商緩存
協(xié)商緩存是利用的是【Last-Modified七蜘,If-Modified-Since】和【ETag、If-None-Match】這兩對請求頭響應(yīng)頭來管理的
Last-Modified 表示本地文件最后修改日期墙懂,瀏覽器會在request header加上If-Modified-Since(上次返回的Last-Modified的值)橡卤,詢問服務(wù)器在該日期后資源是否有更新,有更新的話就會將新的資源發(fā)送回來
Etag就像一個指紋损搬,資源變化都會導(dǎo)致ETag變化碧库,跟最后修改時間沒有關(guān)系柜与,ETag可以保證每一個資源是唯一的
If-None-Match的header會將上次返回的Etag發(fā)送給服務(wù)器,詢問該資源的Etag是否有更新嵌灰,有變動就會發(fā)送新的資源回來
而強制緩存不需要發(fā)送請求到服務(wù)端弄匕,根據(jù)請求頭expires和cache-control判斷是否命中強緩存
比如es的遠程詞庫我們就需要通過配置 Last-Modified和ETag來確定是否要重新獲取遠程詞庫
關(guān)于http狀態(tài)碼的講解
- 200 (成功) 服務(wù)器已成功處理了請求。 通常沽瞭,這表示服務(wù)器提供了請求的網(wǎng)頁粘茄。
- 301 (永久移動) 請求的網(wǎng)頁已永久移動到新位置。 服務(wù)器返回此響應(yīng)(對 GET 或 HEAD 請求的響應(yīng))時秕脓,會自動將請求者轉(zhuǎn)到新位置柒瓣。
- 302 (臨時移動) 服務(wù)器目前從不同位置的網(wǎng)頁響應(yīng)請求,但請求者應(yīng)繼續(xù)使用原有位置來進行以后的請求吠架。
301和302的區(qū)別芙贫,301: 舊地址A的資源不可訪問了(永久移除), 重定向到網(wǎng)址B,搜索引擎會抓取網(wǎng)址B的內(nèi)容傍药,同時將網(wǎng)址保存為B網(wǎng)址磺平。 302: 舊地址A的資源仍可訪問,這個重定向只是臨時從舊地址A跳轉(zhuǎn)到B地址拐辽,這時搜索引擎會抓取B網(wǎng)址內(nèi)容拣挪,但是會將網(wǎng)址保存為A的。
簡單來說俱诸,301的話搜索引擎認為地址a廢棄了菠劝,只抓取b的內(nèi)容,存的網(wǎng)址也是b,302是說a地址還可以提供服務(wù)睁搭,只是暫時從b地址d - 403 (禁止) 服務(wù)器拒絕請求赶诊。
- 404 (未找到) 服務(wù)器找不到請求的網(wǎng)頁。
- 500 (服務(wù)器內(nèi)部錯誤) 服務(wù)器遇到錯誤园骆,無法完成請求舔痪。
比如我的PHP文件中調(diào)用了一個不存在的類
在這里插入圖片描述
調(diào)試狀態(tài)下,如果我們加了ini_set("display_errors",true);
nginx 就會返回200锌唾,并暴露錯誤
502 (錯誤網(wǎng)關(guān)) 服務(wù)器作為網(wǎng)關(guān)或代理锄码,從上游服務(wù)器收到無效響應(yīng)。
- nginx+php 出現(xiàn) 502 bad gateway晌涕,一般這都不是 nginx 的問題滋捶,而是由于 fastcgi 或者 php 的問題導(dǎo)致的,
- php.ini 的 memory_limit 過小
- php-fpm.conf 中 max_children 或者 max_requests 設(shè)置不合理(設(shè)置過小會因為沒有足夠的 cgi 進程處理請求渐排,設(shè)置過大會出現(xiàn)一會兒有響應(yīng)正常炬太,一會兒等很久才有響應(yīng)的情況,一般情況下 children 按 照內(nèi)存計算驯耻,比如說 1G 設(shè)置 64 亲族,2G 設(shè)置 128炒考。這個根據(jù)實際情況自行調(diào)整。另外查看當前的 PHP FastCGI 進程數(shù)是否夠用的命令為:
netstat -anpo | grep "php-cgi" | wc -l
如果實際使用的 FastCGI進程數(shù) 接近預(yù)設(shè)的 FastCGI進程數(shù)霎迫,那么斋枢,說明FastCGI進程數(shù)不夠用,需要增大知给。) - php 程序執(zhí)行時間過長而超時 檢查 nginx 和 fastcgi 中各種 timeout 設(shè)置瓤帚。(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 最多處理多少個請求后便會被關(guān)閉怯邪。在大量處理請求下,如果該值設(shè)置過小會導(dǎo)致 children 頻繁的自殺和建立而浪費 大量時間花墩,若所有的 children 差不多都在這個時候自殺悬秉,則重建前將沒有 children 響應(yīng)請求,于是出現(xiàn) 502 冰蘑『兔冢可以將該值設(shè)置大一些或者是 0 [無限]。
簡單來說祠肥,php-cgi 進程數(shù)不夠用武氓、 php 執(zhí)行時間長、或者是 php-cgi 進程死掉搪柑,都會出現(xiàn) 502 錯誤聋丝。我們來演示一下
在這里插入圖片描述
504 (網(wǎng)關(guān)超時) 服務(wù)器作為網(wǎng)關(guān)或代理,但是沒有及時從上游服務(wù)器收到請求工碾。
- nginx訪問出現(xiàn)504 Gateway Time-out,一般是由于程序執(zhí)行時間過長導(dǎo)致響應(yīng)超時百姓,例如程序需要執(zhí)行90秒渊额,而nginx最大響應(yīng)等待時間為30秒,這樣就會出現(xiàn)超時垒拢。
- 可能原因
1.程序在處理大量數(shù)據(jù)旬迹,導(dǎo)致等待超時。
2.程序中調(diào)用外部請求求类,而外部請求響應(yīng)超時奔垦。
3.連接數(shù)據(jù)庫失敗而沒有停止,死循環(huán)重新連尸疆。
出現(xiàn)這種情況椿猎,我們可以先優(yōu)化程序惶岭,縮短執(zhí)行時間。另一方面犯眠,可以調(diào)大nginx超時限制的參數(shù)按灶,使程序可以正常執(zhí)行。
- 解決方案
- nginx.conf中筐咧,設(shè)置以下幾個參數(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
設(shè)置單個請求的超時時間
php程序中可加入set_time_limit(seconds)設(shè)置最長執(zhí)行時間
例如 set_time_limit(0) 表示不超時。
-
我們通過修改nginx的超時設(shè)置來演示一下504的情況
在這里插入圖片描述
CDN
CDN (全稱 Content Delivery Network)残炮,即內(nèi)容分發(fā)網(wǎng)絡(luò),構(gòu)建在現(xiàn)有網(wǎng)絡(luò)基礎(chǔ)之上的智能虛擬網(wǎng)絡(luò)韭赘,依靠部署在各地的邊緣服務(wù)器,通過中心平臺的負載均衡吉殃、內(nèi)容分發(fā)辞居、調(diào)度等功能模塊,使用戶就近獲取所需內(nèi)容蛋勺,降低網(wǎng)絡(luò)擁塞瓦灶,提高用戶訪問響應(yīng)速度和命中率。CDN 的關(guān)鍵技術(shù)主要有內(nèi)容存儲和分發(fā)技術(shù)
通俗來講抱完,CDN 就像連鎖店贼陶,當我們想吃沙縣小吃的時候,我們不會真的跑到沙縣去吃巧娱,而是附近就可以找到沙縣小吃碉怔,而且全國的沙縣小吃菜單都一樣,每個沙縣小吃就是一個邊緣節(jié)點禁添,那么我們怎么找到離我最近的沙縣小吃呢撮胧,這個時候就用到了CNAME(配置過網(wǎng)站的同學(xué)都見過)和負載均衡系統(tǒng),CNAME 就像你網(wǎng)站的別名老翘,負載均衡系統(tǒng)會根據(jù)用戶的IP 找到最近的邊緣節(jié)點和運營商網(wǎng)絡(luò)芹啥,并根據(jù)節(jié)點的負載情況和相應(yīng)性能,分發(fā)到相應(yīng)的節(jié)點
DNS
DNS(Domain Names System)铺峭,域名系統(tǒng)墓怀,是互聯(lián)網(wǎng)一項服務(wù),是進行域名和與之相對應(yīng)的 IP 地址進行轉(zhuǎn)換的服務(wù)器,簡單來講卫键,DNS相當于一個翻譯官傀履,負責(zé)將域名翻譯成ip地址
- 計算機中DNS的記錄也分成了兩種緩存方式:
瀏覽器緩存:瀏覽器在獲取網(wǎng)站域名的實際 IP 地址后會對其進行緩存,減少網(wǎng)絡(luò)請求的損耗
操作系統(tǒng)緩存:操作系統(tǒng)的緩存其實是用戶自己配置的 hosts 文件
查詢過程
- 首先搜索瀏覽器的 DNS 緩存莉炉,緩存中維護一張域名與 IP 地址的對應(yīng)表,
- 沒有命中則繼續(xù)搜索操作系統(tǒng)的 DNS 緩存
- 若仍然沒有命中钓账,則操作系統(tǒng)將域名發(fā)送至本地域名服務(wù)器碴犬,本地域名服務(wù)器采用遞歸查詢自己的 DNS 緩存,查找成功則返回結(jié)果
- 若本地域名服務(wù)器的 DNS 緩存沒有命中官扣,則本地域名服務(wù)器向上級域名服務(wù)器進行迭代查詢
- 本地域名服務(wù)器將得到的 IP 地址返回給操作系統(tǒng)翅敌,同時自己將 IP 地址緩存起來
- 操作系統(tǒng)將 IP 地址返回給瀏覽器,同時自己也將 IP 地址緩存起
-
至此惕蹄,瀏覽器就得到了域名對應(yīng)的 IP 地址蚯涮,并將 IP 地址緩存起
在這里插入圖片描述