若是你是中高級的前端工程師,相關HTTP問題,在面試的時候被問到的機率很高,且咱們項目中會大量遇到相關的問題。javascript
若是你只是想快速的知道下邊面試官常常問的問題的答案,能夠略過
正式
部分(本文爲HTTP知識詳解部分,其中大量閱讀書籍《圖解HTTP》收穫,和其餘網上資料的總結),直接查看問題回答總結部分。css
若是面試官問你如下問題,你是否能答過來,能答幾道呢?這也是常見的面試題,來試一試吧~html
什麼是三次握手?前端
TCP與UDP的區別?vue
從輸入URL到頁面加載完成,發生了什麼?html5
HTTP響應碼你都知道哪些?都是什麼意思?java
HTTP協議的工做流程?node
HTTP/1.0 和 1.1 現存的哪些問題webpack
HTTP與HTTPS區別nginx
什麼是長連接,爲何須要長鏈接?
HTTP/2的信道複用又爲何能提升性能?
HTTP的緩存機制
XSS和Crsf攻擊都有哪些防範手段?
如何高效利用緩存,上線前端代碼?
一、緩存時間過長,發佈上線了,用戶端還用緩存,會有bug
二、緩存時間太短,重複加載文件過多,浪費帶寬
其實上邊的一些問題,在三面、四面的時候問前端性能優化(文件獲取優化)的時候也是這些問題。
在Web應用中,服務器把網頁傳給瀏覽器,實際上就是把網頁的HTML代碼發送給瀏覽器,讓瀏覽器顯示出來。而瀏覽器和服務器之間的傳輸協議是HTTP 。 HTTP是在網絡上傳輸HTML的協議,用於瀏覽器和服務器的通訊。 HTTP協議屬於應用層,創建在傳輸層協議TCP之上。客戶端經過與服務器須要創建TCP鏈接,以後發送HTTP請求與接收HTTP響應都是經過訪問Socket接口來調用TCP協議實現。 由於HTTP是不存在鏈接這個概念的,只有請求和響應,它們都是數據包。
web:(網頁瀏覽器web browser);
web頁面不會憑空顯示出來。根據Web瀏覽器地址欄中指定的URL,web瀏覽器從Web服務器獲取資源等信息,從而顯示出web頁面。web使用HTTP(超文本傳輸協議)的協議做爲規範,完成從客服端到服務器端等一系列運做流程。Web是簡歷在HTTP協議上的通訊。
協議:指定規則的約定;爲了讓計算機可以通訊,計算機須要定義通訊規則,這些規則就是協議;是數據封裝格式+傳輸 ;協議有多種;
客戶端:像這種經過發送請求獲取服務資源的web瀏覽器等,均可以稱爲客戶端(client)。
爲了瞭解HTTP,咱們必須先了解TCP/IP協議族因一般使用的網絡(包括互聯網)是在TCP/IP協議族的基礎上運做的。而HTTP屬於它內部的一個子集。
TCP/IP
把與互聯網相關聯的協議集合起來總成爲TCP/IP。
也有認爲:TCP/IP是指TCP和IP這兩種協議。
還有認爲:TCP/IP是IP協議的通訊過程當中,使用到的協議族的統稱。
爲何分層?
OSI七層網絡模型
分層 | 功能 | 做用 |
---|---|---|
應用層 | 網絡服務於最終用戶的一個接口 | 提供網絡與用戶應用軟件之間的接口服務,屏蔽了網絡傳輸相關細節 |
表示層 | 數據的表示、安全、壓縮 | 提供格式化的表示和轉換數據服務,如加密和壓縮 |
會話層 | 創建、管理、停止會話 | 提供包括訪問驗證和會話管理在內的創建和維護應用之間通訊的機制 |
傳輸層 | 定義傳輸數據的協議端口號,以及留空和差錯校驗 | 一、提供創建、維護和取消傳輸鏈接功能,負責可靠地傳輸數據(PC);二、向用戶提供可靠的(端到端end-to-end)服務;三、傳輸層向高層屏蔽了下層數據通訊的細節 |
網絡層 | 進行邏輯地址尋址,實現不一樣網絡之間的路徑選擇 | 處理網絡間路由,確保數據及時傳送(路由器),數據包是網絡傳輸的最小數據單位。該層規定了經過怎樣的路徑(傳輸路線)到達對方計算機,並把數據包傳送給對方。 |
數據鏈路層 | 創建邏輯鏈接、進行硬件地址尋址、差錯校驗等功能 | 用來處理連接網絡的硬件部分。負責無錯傳輸數據,確認幀、發錯重傳等(交換機) |
物理層 | 創建、維護、斷開物理鏈接 | 定義物理設備如何傳輸數據;提供機械、電氣、功能和過程特性(網卡、網線、雙絞線、同軸電纜、中繼器) |
網絡五層結構
分層 | 協議 |
---|---|
應用層 | HTTP(超文本傳輸協議)、FTP(文件傳輸協議)、TFTP、SMTP(發送郵件)、SNMP、DNS(域名系統)。。。 |
傳輸層 | TCP(傳輸控制協議)、UDP(用戶數據報協議)。。。 |
網絡層 | ICMP(網際控制消息協議,發送消息,並報告有關數據包的傳送錯誤)、IGMP(互聯組管理協議,IP主機向本地多路廣播路由器報告主機組成員)、IP(網際協議,負責主機和網絡之間尋址和路由數據包)、ARP(地址解析協議,得到同一物理網絡中的硬件主機MAC地址)。。。 |
數據鏈路層 | 由底層網絡定義的協議 |
物理層 | 由底層網絡定義的協議 |
數據包封裝
上層協議數據是如何轉變爲下層協議數據的呢?
這是經過封裝(encapsulate)來實現的。應用程序數據在發送到物理網絡以前,會沿着協議棧從上往下傳遞。每層協議都將在上層協議數據的基礎上加上本身的頭部信息(鏈路層還會加上尾部信息),覺得實現該層功能提供必要的信息。 發送端發送數據時,數據會從上層傳輸到下層,且每通過一層都會被打上該層的頭部信息。而接收端接收數據時,數據會從下層傳輸到上層,傳輸前會把下層的頭部信息刪除。
爲何要這樣封裝呢?
因爲下層協議的頭部信息對上層協議是沒有實際的用途,因此在下層協議傳輸數據給上層協議的時候會把該層的頭部信息去掉,這個封裝過程對於上層協議來講是徹底透明的。這樣作的好處是,應用層只須要關心應用服務的實現,而不用管底層的實現。
一、IP
按層此分,IP位於網絡層。在TCP/IP族中IP指網際協議,不要與IP地址混淆。
IP地址:指明瞭節點被分配到的地址,
MAC地址:是指網卡所屬的固定地址;
IP地址能夠和MAC地址進行配對,IP地址可變換,但MAC地址基本上不會更改。IP間的通訊依賴MAC地址。
不在同一個局域網時,咱們會採用ARP協議(是一種用於解析地址的協議),根據通訊方的IP地址就能夠反查出對應的MAC地址。
二、TCP
客戶端和服務端進行信息發送,是須要建立一個TCP鏈接的。按層此分,TCP(Transimision Control Protocal)位於傳輸層。提供可靠的字節流服務(爲了方便傳輸將大塊數據分割成以報文段爲單位的數據包進行管理)。可靠的傳輸服務是指,可以把數據準確可靠的傳給對方。
TCP 慢啓動
TCP 鏈接會隨着時間進行自我「調諧」,起初會限制鏈接的最大速度,若是數據成功傳輸,會隨着時間的推移提升傳輸的速度。這種調諧則被稱爲 TCP 慢啓動。
2.一、TCP功能:
2.二、TCP的狀態
常見的TCP狀態有:CLOSED, LISTEN, SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT1, CLOSE_WAIT, FIN_WAIT2, LAST_ACK, TIME_WAIT, CLOSED。tcp協議經過tcp狀態來標記當前處於通訊過程的哪一個階段。
2.三、TCP協議與UDP協議
2.四、UDP的應用
2.五、三次握手、數據傳輸、四次揮手
爲了防止服務器開啓無用的連接。
2.5.一、三次握手
爲了準確無誤地將數據傳送到目標處,TCP才用了三次握手策略。
注意:
具體過程以下:
**第一次握手:**客戶端發送帶有SYN標誌的數據段連接請求報文段給服務端, 經過該數據段告訴服務端但願創建鏈接,須要服務端應答,並告訴服務端傳輸的起始序列號,而後進入SYN_SEND狀態,等待服務端的確認。
**第二次握手:**服務端接收到客戶端的SYN報文段後,須要發送ACK信息對這個SYN報文段進行確認。同時,還要發送本身的SYN請求信息。 一是發送ACK告訴客戶端收到了數據段,二是通知客戶端從哪一個序列號作標記。服務端會將上述的信息放到一個報文段(SYN+ACK報文段)中,ack等於seq的值+1,一併發送給客戶端,此時服務端將會進入SYN_RECV狀態。
第三次握手:客戶端接收到服務端的SYN+ACK報文段後,會想服務端發送ACK確認報文段,這個報文段發送完畢後,客戶端和服務端都進入ESTABLISHED狀態,完成TCP三次握手。
當三次握手完成後,TCP協議會爲鏈接雙方維持鏈接狀態。爲了保證數據傳輸成功,接收端在接收到數據包後必須發送ACK報文做爲確認。若是在指定的時間內(這個時間稱爲從新發送超時時間),發送端沒有接收到接收端的ACK報文,那麼就會重發超時的數據。
2.5.二、數據傳輸
2.5.三、四次斷開
** 三、DNS**
DNS是Domain Name Service的縮寫,位於應用層,DNS服務器進行域名和與之對應的IP地址轉換的服務器
一般咱們訪問一個網站,使用的是主機名或者域名來進行訪問的。由於相對於IP地址(一組純數字),域名更容易讓人記住。但TCP/IP協議使用的是IP地址進行訪問的,因此必須有個機制或服務把域名轉換成IP地址。DNS服務就是用來解決這個問題的,它提供域名到IP地址之間的解析服務。 即DNS協議提供統統過域名查找IP地址,或逆向從IP地址反查域名的服務。
DNS域名解析過程:
當用戶在瀏覽器地址欄輸入URL,回車後,咱們要找URL相應的IP地址,怎麼找呢?
如上圖,瀏覽器先找自身緩存,讓其查找是否有緩存的記錄,結果並無發現,此時找向系統緩存,主要去查找了系統中的hosts文件,一樣沒有,此時找向路由器緩存,查看路由器映射表,然而,並無!因而,計算機將域名發給了本地DNS服務器(提供本地鏈接的服務商),本地DNS服務器找不到會將域名發送給其餘服務器,進行遞歸過程,首先會發送到根域名服務器去找,返回頂級域名服務器的IP地址,再請求頂級域名服務器IP返回二級域名服務器IP,再請求二級域名服務器IP返回三級域名服務器IP......直到找到對應的IP地址,返回給瀏覽器。
DNS負載均衡:
DNS負載均衡,又叫作DNS重定向。 CDN(Content Delivery Network)就是利用DNS的重定向技術,DNS服務器會返回一個跟用戶最接近的點的IP地址給用戶,CDN節點的服務器負責響應用戶的請求,提供所需的內容。
DNS返回的IP地址是否每次都同樣?若是每次都同樣是否說明你請求的資源都位於同一臺機器上面,那麼這臺機器須要多高的性能和儲存才能知足億萬請求呢?
其實真實的互聯網世界背後存在成千上百臺服務器,大型的網站甚至更多。可是在用戶的眼中,它須要的只是處理他的請求,哪臺機器處理請求並不重要。DNS能夠返回一個合適的機器的IP給用戶,例如能夠根據每臺機器的負載量,該機器離用戶地理位置的距離等等,這種過程就是DNS負載均衡。
四、TCP/IP族與HTTP相關協議關係
socket 通訊機制
Socket是IPC通訊的一種方式,用於實如今同一主機或者不一樣主機之間的通訊。socket通訊在domain中實現,所謂的 domain 是識別一個socket的方法(socket地址格式)。
socket是一組實現TCP/UDP通訊的接口API,既不管TCP仍是UDP,經過對scoket的編程,均可以實現TCP/UCP。
一、常見的domain:
二、socket的類型:
三、相關的系統調用:
URL、URI
URI用字符串標識某一互聯網資源,而URL表示資源的地點(互聯網上所處的位置)。URL是URI的子集。
一、URI
URI(Uniform Resource Identifier)是統一資源標識符,在某個規則下能把這個資源獨一無二標示出來,好比人的身份證號。
二、URL
URL(Uniform Resource Locator)統一資源定位符,表示資源的地點,URL正是使用瀏覽器訪問WEB頁面時須要輸入的網頁地址
2.一、URL的格式
http
, https
, file
等協議方案名獲取訪問資源時要指定協議類型。也能夠使用data:
或者javascript:
這類指定數據或者腳本程序的方案名。不區分大小寫,最後附一個冒號。後面必須和://
連在一塊兒。key=val
這種形式,多個鍵值對之間用&
隔開。HTTP簡介
HTTP特色
一、無鏈接:限制每次連接只處理一個請求。 服務器處理完客戶的請求,並收到客戶的應答後,即斷開鏈接。採用這種方式能夠節省傳輸時間。 早期這麼作的緣由是請求資源少,追求快。後來經過Connection: Keep-Alive
實現長鏈接 。
二、無狀態: HTTP協議是無狀態協議。無狀態是指協議對於事務處理沒有記憶能力。缺乏狀態意味着若是後續處理須要前面的信息,則它必須重傳,這是爲了更快的處理大量事務,確保協議的可伸縮性,而特地設計的。另外一方面,在服務器不須要先前信息時它的應答就較快。 協議對於發送過的請求或相應都不作持久化處理。HTTP/1.1雖然無狀態,可是增長了cookie技術。有了cookie再用HTTP協議通訊,就能夠管理狀態了。以後會講解。
三、簡單快速: 客戶向服務器請求服務時,只需傳送請求方法和路徑。請求方法經常使用的有GET、HEAD、POST。每種方法規定了客戶與服務器聯繫的類型不一樣。因爲HTTP協議簡單,使得HTTP服務器的程序規模小,於是通訊速度很快。
四、靈活: HTTP容許傳輸任意類型的數據對象。正在傳輸的類型由Content-Type加以標記。 主要體如今兩個方面: 一個是語義上的自由,只規定了基本格式,好比空格分隔單詞,換行分隔字段,其餘的各個部分都沒有嚴格的語法限制。另外一個是傳輸形式的多樣性,不只僅能夠傳輸文本,還能傳輸圖片、視頻等任意數據,很是方便。
六、支持客戶端/服務器模式
七、HTTP是媒體獨立的:這意味着,只要客戶端和服務器知道如何處理的數據內容,任何類型的數據均可以經過HTTP發送。客戶端以及服務器指定使用適合的MIME-type內容類型。
注意:!!!
一、HTTP是無狀態的面向鏈接的協議,無狀態不表明HTTP不能保持TCP鏈接,HTTP使用的不是UDP協議(無鏈接) 二、從HTTP/1.1起,默認都開啓了Keep-Alive,保持鏈接特性,簡單地說,當一個網頁打開完成後,客戶端和服務器之間用於傳輸HTTP數據的TCP鏈接不會關閉,若是客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經創建的鏈接 三、Keep-Alive不會永久保持鏈接,它有一個保持時間,能夠在不一樣的服務器軟件(如Apache)中設定這個時間
它的發展是萬維網協會(World Wide Web Consortium)和Internet工做小組IETF(Internet Engineering Task Force)合做的結果,(他們)最終發佈了一系列的RFC,RFC 1945定義了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定義了今天廣泛使用的一個版本——HTTP /1.1。
1990年問世。並無做爲正式的標準被創建。如今的HTTP其實含有HTTP/1.0以前版本的意思,所以被稱爲HTTP/0.9。只有一個命令
GET
改版本特別簡單,只有一個命令GET
.
GET /index.html
複製代碼
上面命令表示,TCP 鏈接(connection)創建後,客戶端向服務器請求(request)網頁index.html
。
協議規定,服務器只能迴應HTML格式的字符串,不能迴應別的格式,好比頭部信息。
<html>
<body>Hello World</body>
</html>
複製代碼
服務器發送完畢,就關閉TCP鏈接。
1996年5月,HTTP/1.0 版本發佈,內容大大增長。 增長了不少命令、增長status、code和header、多字符集支持、多部分發送、權限、緩存等。 描述HTTP 1.0規範的RFC 1945。
HTTP/1.0 新特性:
一、增長方法: 除了GET
方法,還引入了POST
方法和HEAD
方法;
二、 任何格式的內容均可以發送。這使得互聯網不只能夠傳輸文字,還能傳輸圖像、視頻、二進制文件;
三、 HTTP請求和迴應的格式也變了。除了數據部分,每次通訊都必須包括頭信息(HTTP header),用來描述一些元數據。
四、 其餘的新增功能還包括狀態碼(status code)、多字符集支持、多部分發送(multi-part type)、權限(authorization)、緩存(cache)、內容編碼(content encoding)等。
HTTP/1.0缺點:
缺點:每一個TCP連接只能發送一個請求。 發送數據完畢,鏈接就關閉,若是還要請求其餘資源,就必須再新建一個鏈接。
解決方法:使用,Connection:keep-alive
1997年1月,HTTP/1.1 版本發佈,只比 1.0 版本晚了半年。它進一步完善了 HTTP 協議,一直用到了20年後的今天,直到如今仍是最流行的版本。
在HTTP/1.0的基礎上,支持了持久鏈接、增長了pipeline、增長host和其餘一些命令。
描述HTTP 1.1規範的RFC 2616。
HTTP/1.1 新特性
一、 引入了持久鏈接(persistent connection),即TCP鏈接默認不關閉,能夠被多個請求複用,不用聲明Connection: keep-alive
。
客戶端和服務器發現對方一段時間沒有活動,就能夠主動關閉鏈接。不過,規範的作法是,客戶端在最後一個請求時,發送Connection: close
,明確要求服務器關閉TCP鏈接。
Connection: close
複製代碼
目前,對於同一個域名,大多數瀏覽器容許同時創建6個持久鏈接。
二、 HTTP管線化(HTTP pipelining)
引入了管道機制(pipelining),即在同一個TCP鏈接裏面,客戶端能夠同時發送多個請求。這樣就進一步改進了HTTP協議的效率。
三、與HTTP/1.0不一樣,還有Content-Length 字段;
由於一個 TCP鏈接能夠發多個請求,那如今就會傳送多個迴應,勢必就要有一種機制,區分數據包是屬於哪個迴應的。因此這個字段用於聲明本次迴應的數據長度。
而HTTP/1.0版本中, 瀏覽器發現服務器關閉了TCP鏈接,就代表收到的數據包已經全了,因此 Content-Length
字段 不是必須的。
四、相對於HTTP/1.0,1.1版還新增了許多動詞方法:PUT
、PATCH
、HEAD
、 OPTIONS
、DELETE
。
另外,客戶端請求的頭信息新增了Host
字段,用來指定服務器的域名。
http/1.1缺點:
一、"隊頭堵塞"(Head-of-line blocking): 1.1版容許複用TCP鏈接,可是同一個TCP鏈接裏面,全部的數據通訊是按次序進行的。服務器只有處理完一個迴應,纔會進行下一個迴應。要是前面的迴應特別慢,後面就會有許多請求排隊等着。
解決方法:
二、HTTP頭部巨大
三、明文傳輸--帶來的不安全性
四、服務器不能主動推送
**SPDY **
上面咱們提到,因爲HTTP/1.1的缺點,想解決的話,咱們會合並腳本和樣式表、雪碧圖、將圖片嵌入CSS代碼、域名分片(domain sharding)等等的方式來提升性能。不過這些優化都繞開了協議,直到2009年,谷歌公開了自行研發的 SPDY 協議,主要解決HTTP/1.1效率不高的問題。谷歌推出SPDY,纔算是正式改造HTTP協議自己。下降延遲,壓縮header等等,SPDY的實踐證實了這些優化的效果,也最終帶來HTTP/2的誕生。
簡介:
2015年,HTTP/2 發佈。它不叫 HTTP/2.0,是由於標準委員會不打算再發布子版本了,下一個新版本將是 HTTP/3。 全部數據以二進制傳輸、同一個鏈接裏面發送多個請求再也不須要按照順序來了、頭信息壓縮以及推送(服務端能夠主動發起請求了)等提升了效率的功能
HTTP/2由兩個規範(Specification)組成:
HTTP/2新特性:
一、二進制協議
HTTP/2基於SPDY的,是一個二進制協議,而HTTP/1.x是一個超文本協議; HTTP/1.1 版的頭信息確定是文本(ASCII編碼),數據體能夠是文本,也能夠是二進制。HTTP/2 則是一個完全的二進制協議,頭信息和數據體都是二進制,而且統稱爲"幀"(frame):頭信息幀和數據幀。
HTTP/2 將請求和響應數據分割爲更小的幀,而且它們採用二進制編碼。
二、多路複用
HTTP/2能夠避免 "隊頭堵塞" ,由於HTTP/2 複用TCP鏈接,在一個鏈接裏,客戶端和瀏覽器均可以同時發送多個請求或迴應,並且不用按照順序一一對應; 雙向的、實時的通訊,就叫作多工;
你們能夠經過 該連接 直觀感覺下 HTTP/2 比 HTTP/1 到底快了多少。
三、 HTTP/2 引入了頭信息壓縮機制(header compression)
四、 HTTP/2 容許服務器未經請求,主動向客戶端發送資源,這叫作服務器推送(server push)
用於HTTP協議交互的信息被稱爲HTTP報文。請求端(客戶端)的HTTP報文叫作請求報文,響應端(服務端)的叫作響應報文。一定包含HTTP首部
HTTP報文構成:報文首部、空行、報文主體。一般,並不必定要有報文主體。
請求報文和響應報文的構成
從上邊圖能夠看出,請求報文:請求行、各類首部字段、空行;響應報文:狀態行、各類首部字段、報文主體;
通常有四種首部:通用首部、請求首部、響應首部和實體首部;
請求報文的構成:
請求行:包括用於請求的方法,請求URI和HTTP版本。以下圖請求報文的構成:POST方法、請求URI:/form/entry 、協議版本:HTTP/1.1
請求首部字段:包含請求各類條件和屬性的各種首部。
響應報文:
狀態行:包含代表響應結果的狀態碼,緣由短語和HTTP版本;
響應首部字段:表示響應的各類條件和屬性的各種首部;
響應體:具體的數據,以下圖返回的html
ps:注意事項
一、在起始行(請求行和狀態行)中,每兩個部分之間用空格隔開,最後一個部分後面應該接一個換行,嚴格遵循ABNF
語法規範;
二、首部字段:
_
:
三、空行
很重要,用來區分開頭部
和實體
。
問: 若是說在頭部中間故意加一個空行會怎麼樣?
那麼空行後的內容所有被視爲實體。
咱們使用 Chrome瀏覽器的開發者工具中的
Network
來查看瀏覽器和服務器之間的通訊;
step1:在瀏覽器地址欄中輸入www.baidu.com
,在ctrl+f12
或在菜單中選擇「視圖」,「開發者」,「開發者工具」,就能夠顯示開發者工具 ;
step2: 咱們點Network
,確保第一個小紅燈亮着(抓包工具),Chrome就會記錄全部瀏覽器和服務器之間的通訊:
step3: 在Network
中,定位到第一條記錄,點擊,右側將顯示Request Headers
,點擊右側的view source
,咱們就能夠看到瀏覽器發給百度服務器的請求:
step4:一樣你還能夠看Response Headers
,點擊view source
,顯示服務器返回的原始響應數據
Content-Type
指示響應的內容,這裏是text/html
表示HTML網頁。 瀏覽器就是依靠Content-Type
來判斷響應的內容是網頁仍是圖片,是視頻仍是音樂。瀏覽器並不靠URL來判斷響應的內容, 因此,即便URL是http://example.com/abc.jpg
,它也不必定就是圖片。
step5:點擊Response
是響應體的內容是HTML源碼。
當瀏覽器讀取到百度首頁的HTML源碼後,它會解析HTML,顯示頁面,而後,根據HTML裏面的各類連接,再發送HTTP請求給新浪服務器,拿到相應的圖片、視頻、Flash、JavaScript腳本、CSS等各類資源,最終顯示出一個完整的頁面。因此咱們在Network
下面能看到不少額外的HTTP請求。
curl
工具查看報文step1: 在命令行工具中輸入下面命令
curl -v www.baidu.com
複製代碼
固然還能夠使用其餘的抓包工具查看,在這就不一一列舉了。
注意方法名要大寫。
方法 | 說明 | 支持版本 |
---|---|---|
GET | 獲取資源。請求指定的頁面信息,並返回實體主體。 | HTTP/1.0以上版本都支持 |
POST | 向服務器發送數據,傳輸實體主題。請求服務器接受所指定的文檔做爲對所標識的URI的新的從屬實體。 | HTTP/1.0以上版本都支持 |
PUT | 傳輸文件。HTTP/1.1的PUT不帶驗證機制,因此通常的web網站也不會使用此方法。 | HTTP/1.0以上版本都支持 |
HEAD | 只請求頁面的首部。 | HTTP/1.0以上版本都支持 |
DELETE | 請求服務器刪除指定的頁面。與PUT相反的方法。HTTP/1.1的DELETE也不帶驗證機制,因此通常的web網站也不會使用此方法。 | HTTP/1.0以上版本都支持 |
OPTIONS | 詢問支持的方法。此方法用來查詢針對請求URI指定的資源支持的方法。(跨域時,有可能會用到,複雜請求也可會用到) | HTTP/1.1以上版本都支持 |
TRACE | 追蹤路徑。此方法讓web服務器將以前的請求通訊返回給客戶端的方法。此方法不經常使用,容易引起XST(跨站追蹤)攻擊。 | HTTP/1.1以上版本都支持 |
CONNECT | 要求用隧道協議鏈接代理。主要使用SSL(安全套接層)和TLS(傳輸層安全)協議把通訊內容加密後經網絡隧道傳輸。 | HTTP/1.1以上版本都支持 |
LINK | 請求服務器創建連接關係。 | HTTP/1.0版本支持,HTTP/1.1已經廢除 |
UNLINK | 斷開連接關係。 | HTTP/1.0版本支持,HTTP/1.1已經廢除 |
後又有這樣一些具體的差異:
緩存
的角度,GET 請求會被瀏覽器主動緩存下來,留下歷史記錄,而 POST 默認不會。編碼
**的角度,GET 只能進行 URL 編碼,只能接收 ASCII 字符,而 POST 沒有限制。參數
**的角度,GET 通常放在 URL的後面拼接 上,所以不安全,POST 放在請求體中,更適合傳輸敏感信息。安全
**角度, POST的安全性要比GET的安全性高。長度限制
的角度,GET請求有具體長度限制,通常不超過1024KB,而POST理論上沒有,可是瀏覽器自己都有一個界限。冪等性
的角度,GET
是冪等**的,而POST
不是。(冪等
表示執行相同的操做,結果也是相同的)TCP
**的角度,GET和POST都是TCP鏈接,並沒有實質的區別.可是因爲HTTP/瀏覽器的限定,致使它們在應用過程當中體現出了一些不一樣.GET產生一個數據包,POST產生兩個數據包.對於GET請求,瀏覽器會把http header 和 data 一併發出去,服務器響應200(返回數據).而對於POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data,服務器響應200 ok
(火狐瀏覽器除外,它的 POST 請求只發一個 TCP 包)狀態碼的職責是當客戶端向服務器端發送請求時,描述返回的請求結果。藉助狀態碼,用戶能夠知道服務器端是正常處理請求,仍是出現了錯誤。
響應碼 | 含義、應用 | |
---|---|---|
1** | 表示臨時的響應。客戶端在收到常規響應以前,應準備接收一個或多個 1xx 響應。 | |
100 | 請求者應當繼續提出請求。 服務器返回此代碼表示已收到請求的第一部分,正在等待其他部分。 | |
101 | 切換協議。請求者已要求服務器切換協議,服務器已確認並準備切換。針對請求頭的Upgrade返回的信息。代表服務器正在切換到指定的協議。好比websocket 、升級到http2 |
|
2** | 代表服務器成功的接受了客戶端請求 | |
200 | 成功。客戶端請求已成功。一般,這表示服務器提供了請求的網頁。 | |
201 | 已建立。請求成功而且服務器建立了新的資源。經常使用於POST,PUT 請求,代表請求已經成功,並新建了一個資源。並在響應體中返回路徑。 | |
202 | 已接受。請求已經接收到,但沒有響應,稍後也不會返回一個異步請求結果。 該狀態碼適用於等待其餘進程處理或者批處理的場景。 | |
203 | 非權威性信息。服務器已成功處理了請求,但返回的信息可能來自另外一來源。主要用於其餘資源的鏡像和備份。除了前面的狀況,首選仍是200。 | |
204 | 無內容。服務器成功處理了請求,沒有返回任何內容,可是頭信息有用。用戶代理(瀏覽器)會更新緩存的頭信息。用戶代理: 代替用戶運行的軟件,如web瀏覽器,或者郵件閱讀器。 | |
205 | 重置內容。告訴用戶代理(瀏覽器)重置發送該請求的文檔。 | |
206 | 部份內容。代表已部分下載了一個文件。能夠續傳損壞的下載,或者將下載拆分爲多個併發的流。服務器成功處理了部分 GET 請求。當客戶端使用Range請求頭時,返回該狀態碼。curl -v --header "Range:bytes=0-3" ,經過curl發起http請求-->響應行爲:HTTP/1.1 206 Partial Content |
|
207 | 多狀態(WebDAV)。此消息以前應該還有一條 XML 消息,其中可能包含幾個單獨的響應代碼,具體取決於發出了多少個子請求。 | |
3** | 重定向。例如,瀏覽器可能不得不請求服務器上的不一樣頁面,或經過代理服務器重複該請求。 | |
301 | 已永久移動。此請求和以後全部的請求都應該轉到指定的 URI。由於有些客戶端會把請求方式method改爲GET。因此該狀態碼建議GET和HEAD方法中使用。搜索引擎會更新地址到資源的連接(SEO中‘link-judge’被髮送到新的URL)。 | |
302 | 對象已移動。將來可能還會有新的修改。對於基於表單的身份驗證,此消息一般表示爲「對象已移動」。請求的資源臨時駐留在不一樣的 URI。因爲重定向有時可能會改變,客戶端未來在請求時應該繼續使用 RequestURI。只有在 CacheControl 或 Expires 標題字段中指示,此響應纔可以緩存。搜索引擎不會更改URL到資源的。應用:負載均衡。 | |
304 | 未修改。客戶端請求的文檔已在其緩存中,文檔自緩存以來還沒有被修改過。客戶端使用文檔的緩存副本,而不從服務器下載文檔。若是想使用200狀態碼達到相同304效果,須要強制緩存,須要額外的請求頭:Cache-Control, Expires, Vary | |
305 | 使用代理。 | |
307 | 臨時重定向。基本和302相同。惟一的區別是這個狀態碼嚴格禁止瀏覽器到新URL請求資源時修改原來的請求方式和請求體。好比,原來使用POST,此次仍是要使用POST。若是想要用PUT方法去修改一個服務器上沒有的資源,能夠用303狀態碼。若是想要把一個POST方法改成GET,請使用303。 | |
308 | 永久重定向。基本和301相同。可是嚴格禁止修改請求方式和請求體。 | |
4** | 客戶端錯誤,域名已中止加速服務。。例如,客戶端請求不存在的頁面,客戶端未提供有效的身份驗證信息。 | |
400 | 請求語法有問題,服務器沒法識別。例如,沒有host請求頭字段,或者設置了超過一個的host請求頭字段。 | |
401 | 訪問請求驗證失敗。缺少有效的身份認證憑證,通常多是未登錄。登錄後通常都解決問題。 | |
401.1 | 用戶名或密碼無效致使登陸失敗。 | |
401.2 | 服務器配置致使登陸失敗。 | |
401.3 | 因爲 ACL 對資源的限制而未得到受權。表示存在 NTFS 權限問題。即便您對試圖訪問的文件具有相應的權限,也可能發生此錯誤。例如,若是 IUSR 賬戶無權訪問 C:WinntSystem32Inetsrv 目錄,您會看到這個錯誤。 | |
401.4 | 篩選器受權失敗。 | |
401.5 | ISAPI/CGI 應用程序受權失敗。 | |
401.7 | 由 Web 服務器上的 URL 驗證策略拒絕訪問。這個錯誤代碼爲 IIS 6.0 所專用。 | |
402 | 保留,未來使用 | |
403 | 服務器拒絕響應。權限不足。 | |
404 | URL無效或者URL有效可是沒有資源。 | |
405 | 方法禁用。請求方式Method不容許。可是GET和HEAD屬於強制方式,不能返回這個狀態碼。 | |
406 | 不接受。資源類型不符合服務器要求。 | |
407 | 須要代理受權。要求進行代理身份驗證。 | |
408 | 請求超時。服務器等候請求時發生超時。 | |
409 | 服務器在完成請求時發生衝突。 服務器必須在響應中包含有關衝突的信息。 | |
410 | 已刪除。若是請求的資源已永久刪除,服務器就會返回此響應。410不一樣於404,若是資源之前有如今被永久刪除了可以使用410代碼,網站設計人員可經過301代碼指定資源的新位置。 | |
411 | 須要有效長度。服務器不接受不含有效內容長度Content-Length標頭字段的請求。 | |
412 | 未知足前提條件。客戶端請求信息的先決條件錯誤。 | |
413 | 請求實體過大。因爲請求的實體過大,服務器沒法處理,所以拒絕請求。爲防止客戶端的連續請求,服務器可能會關閉鏈接。若是隻是服務器暫時沒法處理,則會包含一個Retry-After的響應信息。 | |
414 | 請求的 URI 過長。請求的 URI(一般爲網址)過長,服務器沒法處理。 | |
415 | 不支持的媒體類型。服務器沒法處理請求附帶的媒體格式 | |
416 | 客戶端請求的範圍無效。 | |
417 | 服務器沒法知足Expect的請求頭信息。 | |
5** | 服務器錯誤。 | |
500 | 服務器內部錯誤。未捕獲。 | |
501 | 服務器不具有完成請求的功能。 例如,服務器沒法識別請求方法時可能會返回此代碼。 | |
502 | 錯誤網關。Web 服務器做爲網關或代理服務器時,從上游服務器收到了無效響應。此類錯誤通常與服務器自己有關(與請求無關)、負載均衡。 | |
503 | 服務不可用。目前服務器沒法使用,通常是由於服務器超載或中止維護。一般,這只是暫時狀態。通常還會伴隨着返回一個響應頭Retry-After: 說明恢復服務的估計時間。 | |
504 | 網關超時。服務器做爲網關或者代理,不能及時從上游服務器獲取響應返回給客戶端。 | |
505 | HTTP 版本不受支持。發出的請求http版本服務器不支持。若是請求經過http2發送,服務器不支持http/2,就會返回該狀態碼。 |
這麼多你們可能記不住,不過下邊常見的狀態碼,跟咱們前端是息息相關的,須要記住。
常見狀態碼可見問題部分:HTTP響應碼你都知道哪些?都是什麼意思?
HTTP首部字段有首部字段名和首部字段值構成,中間用冒號
:
分割
通常有四種首部:通用首部、請求首部、響應首部和實體首部;
首部字段:
字段名不區分大小寫
字段名不容許出現空格,不能夠出現下劃線_
字段名後面必須緊接着:
字段值對應單個HTTP首部字段能夠有多個值
Keep-Alive: timeout=15,max=100
複製代碼
如下是HTTP\1.1規範定義的首部字段
首部字段名 | 說明 |
---|---|
Cache-Control | 控制緩存行爲 |
Connection | 連接的管理 |
Date | 代表建立 HTTP 報文的日期和時間 |
Pragma | 報文指令 |
Trailer | 報文尾部的首部 |
Trasfer-Encoding | 指定報文主體的傳輸編碼方式 |
Upgrade | 升級爲其餘協議, 首部字段 Upgrade 用於檢測 HTTP 協議及其餘協議是否可以使用更高的版本進行通訊, 其參數值能夠用來指定 一個徹底不一樣的通訊協議。 |
Via | 代理服務器信息 使用首部字段 Via 是爲了追蹤客戶端與服務器之間的請求和響應報文的傳輸路徑。 |
Warning | 錯誤通知 |
首部字段名 | 說明 |
---|---|
Accept | 用戶代理可處理的媒體類型 |
Accept-Charset | 優先的字符集 |
Accept-Encoding | 優先的編碼 |
Accept-Langulage | 優先的語言 |
Authorization | Web認證信息 |
Expect | 期待服務器的特定行爲 |
From | 用戶的電子郵箱地址 |
Host | 請求資源所在的服務器 |
If-Match | 比較實體標記 |
If-Modified-Since | 比較資源的更新時間 |
If-None-Match | 比較實體標記 |
If-Range | 資源未更新時發送實體Byte的範圍請求 |
If-Unmodified-Since | 比較資源的更新時間(和If-Modified-Since相反) |
Max-Forwards | 最大傳輸跳數 |
Proxy-Authorization | 代理服務器須要客戶端認證 |
Range | 實體字節範圍請求 |
Referer | 請求中的URI的原始獲取方 |
TE | 傳輸編碼的優先級 |
User-Agent | HTTP客戶端程序的信息 |
首部字段名 | 說明 |
---|---|
Accept-Ranges | 是否接受字節範圍 |
Age | 資源的建立時間 |
ETag | 資源的匹配信息 |
Location | 客戶端重定向至指定的URI |
Proxy-Authenticate | 代理服務器對客戶端的認證信息 |
Retry-After | 再次發送請求的時機 |
Server | 服務器的信息 |
Vary | 代理服務器緩存的管理信息 |
www-Authenticate | 服務器對客戶端的認證 |
首部字段名 | 說明 |
---|---|
Allow | 資源可支持的HTTP方法 |
Content-Encoding | 實體的編碼方式 |
Content-Language | 實體的天然語言 |
Content-Length | 實體的內容大小(字節爲單位) |
Content-Location | 替代對應資源的URI |
Content-MD5 | 實體的報文摘要 |
Content-Range | 實體的位置範圍 |
Content-Type | 實體主體的媒體類型 |
Expires | 實體過時時間 |
Last-Modified | 資源的最後修改時間 |
還有使用頻率比較高的首部字段有:Cookie
、SetCookie
、Contene-Disposition
等
HTTP 首部字段將定義成緩存代理和非緩存代理的行爲,分紅 2 種類型。
端到端首部(End-to-end): 分在此類別中的首部會轉發給請求 / 響應對應的最終接收目標,且必須保存在由緩存生成的響應中,另外規 定它必須被轉發。
逐跳首部(Hop-by-hop):分在此類別中的首部只對單次轉發有效,會因經過緩存或代理而再也不轉發。HTTP/1.1 和以後版本中,若是要使用 hop-by-hop 首部,需提供 Connection 首部字段。
下面列舉了 HTTP/1.1 中的逐跳首部字段。除這 8 個首部字段以外,其餘全部字段都屬於端到端首部。
字段 | 說明 | 示例 |
---|---|---|
Accept | 可接收的響應內容類型 | Accept:text/plain (文本類型) |
Accept-Charset | 可接收的字符集 | Accept-Charset: utf-8 |
Accept-Encoding | 可接受的響應內容的編碼方式 | Accept-Encoding: gzip, deflate |
Accept-Language | 可接受的響應內容語言列表 | Accept-Language: en-US |
Accept-Datetime | 可接受的按照時間來表示的響應內容版本 | Accept-Datetime: Sat, 26 Dec 2015 17:30:00 GMT |
Authorization | HTTP協議中須要認證資源的認證信息 | Authorization: Basic OSdjJGRpbjpvcGVuIANlc2SdDE== |
Cache-Control | 請求/回覆中的,是否使用緩存機制 | Cache-Control: no-cache |
Connection | 客戶端想要優先使用的鏈接類型 | Connection: keep-alive Connection: Upgrade |
Content-Length | 以8進製表示的請求體的長度 | Content-Length: 348 |
Content-Type | 請求體的MIME類型 | Content-Type: application/x-www-form-urlencoded |
Date | 發送該消息的日期和時間 | Date: Dec, 26 Dec 2015 17:30:00 GMT |
Expect | 表示客戶端要求服務器作出特定的行爲 | Expect: 100-continue |
From | 發起此請求的用戶的郵件地址 | From: user@a.com |
Host | 服務器域名和端口號,默認端口可省略 | Host: www.a.com:80 or www.a.com |
If-Match | 主要用於PUT,實體匹配才能夠操做 | If-Match: "9jd00cdj34pss9ejqiw39d82f20d0ikd" |
If-Modified-Since | 資源未被修改的狀況下返回304未修改 | If-Modified-Since: Dec, 26 Dec 2015 17:30:00 GMT |
User-Agent | 瀏覽器的身份標識字符串 | User-Agent: Mozilla/ |
Upgrade | 要求服務器升級到一個高版本協議 | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
Via | 告訴服務器,這個請求是由哪一個代理髮出的 | Via: 1.0 fred, 1.1 a.com.com (Apache/1.1) |
Referer | 表示跳轉到當前頁面的以前的頁面 | Referer: a.com/nodejs |
Origin | 發起一個針對跨域資源共享的請求 | Origin: www.a.com |
Connection
Connection 首部字段具有以下兩個做用。
一、控制再也不轉發給代理的首部字段
二、管理持久鏈接
Connection: close
複製代碼
HTTP/1.1 版本的默認鏈接都是持久鏈接。爲此,客戶端會在持久鏈接上連續發送請求。當服務器端想明確斷開鏈接時,則指定Connection
首部字段的值爲 close
。
Pragma
Pragma
是 HTTP/1.1 以前版本的歷史遺留字段,僅做爲與 HTTP/1.0 的向後兼容而定義。 規範定義的形式惟一,以下所示。
Pragma: no-cache
複製代碼
該首部字段屬於通用首部字段,但只用在客戶端發送的請求中。客戶端會要求全部的中間服務器不返回緩存 的資源。
全部的中間服務器若是都能以 HTTP/1.1 爲基準,那直接採用Cache-Control: no-cache
指定緩存的處理方式 是最爲理想的。但要總體掌握所有中間服務器使用的 HTTP 協議版本倒是不現實的。所以,發送的請求會同 時含有下面兩個首部字段。
Cache-Control: no-cache
Pragma: no-cache
複製代碼
經過指定首部字段 Cache-Control的指令,就能操做緩存的工做機制。
語法格式:
指令的參數是可選的,多個指令之間經過','分隔。
Cache-Control:private,max-age=0,no-cache
複製代碼
緩存請求指令
指令 | 參數 | 說明 |
---|---|---|
no-cache | 無 | 強制向源服務器再次驗證 |
no-store | 無 | 不緩存請求或響應的任何內容 |
max-age = [ 秒] | 必需 | 響應的最大Age值 |
max-stale( = [ 秒]) | 可省略 | 接收已過時的響應 |
min-fresh = [ 秒] | 必須 | 指望在指定時間內的響應仍有效 |
no-transform | 無 | 代理不可更改媒體類型 |
cache-extension | - | 新指令標記(token) |
緩存響應指令
指令 | 參數 | 說明 |
---|---|---|
public | 無 | 可向任意方提供響應的緩存 |
private | 可省略 | 僅向特定用戶返回響應 |
no-cache | 可省略 | 緩存前必須先確認其有效性 |
no-store | 無 | 不緩存請求或響應的任何內容 |
no-transform | 無 | 代理不可更改媒體類型 |
must-revalidate | 無 | 可緩存但必須再向源服務器進行確認 |
proxy-revalidate | 無 | 要求中間緩存服務器對緩存的響應有效性再進行 確認 |
max-age = [ 秒] | 必須 | 響應的最大Age值 |
s-maxage = [ 秒] | 必須 | 公共緩存服務器響應的最大Age值,max-age 長得比較像,可是區別在於s-maxage是針對代理服務器的緩存時間 |
cache-extension | - | 新指令標記(token) |
Content-Type(內容類型), 通常是指網頁中存在的 Content-Type,用於定義網絡文件的類型和網頁的編碼,決定瀏覽器將以什麼形式、什麼編碼讀取這個文件。
Content-Type 標頭告訴客戶端實際返回的內容的內容類型。
關於字符的編碼,1.0版規定,頭信息必須是 ASCII 碼,後面的數據能夠是任何格式。所以,服務器迴應的時候,必須告訴客戶端,數據是什麼格式,這就是Content-Type
字段的做用。
語法格式:
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=something
複製代碼
常見的媒體格式類型以下:
媒體格式類型 | 說明 |
---|---|
text/html | HTML格式 |
text/plain | 純文本格式 |
text/xml | XML格式 |
image/gif | gif圖片格式 |
image/jpeg | jpg圖片格式 |
image/png | png圖片格式 |
以application開頭的媒體格式類型:
以application開頭的媒體格式類型 | 說明 |
---|---|
application/xhtml+xml | XHTML格式 |
application/xml | XML數據格式 |
application/atom+xml | Atom XML聚合格式 |
application/json | JSON數據格式 |
application/pdf | pdf格式 |
application/msword | Word文檔格式 |
application/x-www-form-urlencoded | 最多見的post提交數據的方式。 |
application/octet-stream | 二進制流數據(如常見的文件下載) |
另一種常見的媒體格式是上傳文件之時使用的:
媒體格式類型 | 說明 |
---|---|
multipart/form-data | 須要在表單中進行文件上傳時,就須要使用該格式 |
管理服務器與客戶端之間狀態的 Cookie,雖然沒有被編入標準化 HTTP/1.1 的 RFC2616 中,但在 Web 網 站方面獲得了普遍的應用。 Cookie 的工做機制是用戶識別及狀態管理。Web 網站爲了管理用戶的狀態會經過 Web 瀏覽器,把一些數據 臨時寫入用戶的計算機內。接着當用戶訪問該Web網站時,可經過通訊方式取回以前發放的 Cookie。
爲 Cookie 服務的首部字段
首部字段名 | 說明 | 首部類型 |
---|---|---|
Set-Cookie | 開始狀態管理所使用的Cookie信息 | 響應首部字段 |
Cookie | 服務器接收到的Cookie信息 | 請求首部字段 |
Cookie的處理流程:
一、 客戶端第一次訪問服務器的時候服務器經過響應頭向客戶端發送Cookie,屬性之間用分號空格分隔
二、 客戶端接收到Cookie以後保存在本地
三、 之後客戶端再請求服務器的時候會把此Cookie發送到服務器端
語法格式:
Set-Cookie: status=enable; expires=Tue, 05 Jul 2011 07:26:31 GMT; path=/; domain=.a.com;
複製代碼
當服務器準備開始管理客戶端的狀態時,會事先告知各類信息。下面的表格列舉了 Set-Cookie 的字段值。
Set-Cookie 字段的屬性
屬性 | 說明 |
---|---|
NAME=VALUE | 賦予 Cookie 的名稱和其值(必需項) |
expires=DATE | Cookie的有效期(若不明確指定則默認爲瀏覽器關閉前爲止) |
max-age = [ 秒] | Cookie多少秒後過時(若不明確指定則默認爲瀏覽器關閉前爲止) |
path=PATH | 將服務器上的文件目錄做爲Cookie的適用對象(若不指定則默認爲文檔 所在的文件目錄) |
domain=域名 | 做爲 Cookie 適用對象的域名 (若不指定則默認爲建立 Cookie 的服務 器的域名) |
Secure | 僅在 HTTPS 安全通訊時纔會發送 Cookie |
HttpOnly | 加以限制,使 Cookie 不能被 JavaScript 腳本訪問,防止XSS攻擊產生 |
expires 屬性
Cookie 的 expires 屬性指定瀏覽器可發送 Cookie 的有效期。 當省略 expires 屬性時,其有效期僅限於維持瀏覽器會話(Session)時間段內。這一般限於瀏覽器應用程序被關閉以前。 另外,一旦 Cookie 從服務器端發送至客戶端,服務器端就不存在能夠顯式刪除 Cookie 的方法。但可經過覆蓋已過時的 Cookie,實現對客戶端 Cookie 的實質性刪除操做。
Cookie: status=enable
複製代碼
首部字段 Cookie 會告知服務器,當客戶端想得到 HTTP 狀態管理支持時,就會在請求中包含從服務器接收到的 Cookie。接收到多個 Cookie 時,一樣能夠以多個 Cookie 形式發送。
session是另外一種記錄客戶狀態的機制,不一樣的是Cookie保存在客戶端瀏覽器中,而session保存在服務器上
客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上,這就是session。客戶端瀏覽器再次訪問時只須要從該Session中查找該客戶的狀態就能夠了
將登錄信息等重要信息存放爲session、其餘信息若是須要保留,能夠放在cookie中
經過⽹絡獲取內容既速度緩慢⼜開銷巨⼤。較⼤的響應須要在客戶端與服務器之間進⾏屢次往返通訊,
這會延遲瀏覽器得到和處理內容的時間,還會增長訪問者的流量費⽤。所以,緩存並重複利⽤以前獲取
的資源的能⼒成爲性能優化的⼀個關鍵⽅⾯。
數據傳輸
,節省了網費。性能
速度
⼴義的緩存,能夠分爲這四個 :
Service Worker Cache:
Service Worker 借鑑了 Web Worker的 思路,即讓 JS 運行在主線程以外,因爲它脫離了瀏覽器的窗體,所以沒法直接訪問DOM
。雖然如此,但它仍然能幫助咱們完成不少有用的功能,好比離線緩存
、消息推送
和網絡代理
等功能。其中的離線緩存
就是 Service Worker Cache。
Memory Cache:
內存緩存,從效率上講它是最快的。可是從存活時間來說又是最短的,當渲染進程結束後,內存緩存也就不存在了。
HTTP緩存有多種規則,根據是否須要從新向服務器發起請求來分類,可將其分爲強制緩存,對比緩存。
一、強緩存
瀏覽器中的緩存做用分爲兩種狀況,一種是須要發送HTTP
請求,一種是不須要發送。
首先是檢查強緩存,這個階段不須要
發送HTTP請求。
那麼瀏覽器是如何檢查的呢?
咱們知道,在沒有緩存數據的時候,瀏覽器向服務器請求數據時,服務器會將數據和緩存規則一併返回,緩存規則信息包含在響應header中。
注意:
在
HTTP/1.0
和HTTP/1.1
當中,這個字段是不同的。在早期,也就是HTTP/1.0
時期,使用的是Expires,而HTTP/1.1
使用的是Cache-Control。當Expires和Cache-Control同時存在的時候,Cache-Control會優先考慮。
Expires
Expires
:即過時時間,存在於服務端返回的響應頭中,告訴瀏覽器在這個過時時間以前能夠直接從緩存裏面獲取數據,無需再次請求。
好比下面這樣:
Expires: Wed, 22 Apr 2020 08:41:00 GMT
複製代碼
表示資源在2020年4月22號8點41分
過時,過時了就得向服務端發請求。
這個方式看上去沒什麼問題,合情合理,但其實潛藏了一個坑,那就是服務器的時間和瀏覽器的時間可能並不一致,那服務器返回的這個過時時間可能就是不許確的。所以這種方式很快在後來的HTTP/1.1版本中被拋棄了。
Cache-Control
Cache-Control: 在HTTP/1.1中,請求/響應頭,緩存控制字段,精確控制緩存策略。
它和Expires
本質的不一樣在於它並無採用具體的過時時間點
這個方式,而是採用過時時長來控制緩存,對應的字段是max-age。好比這個例子:
Cache-Control:max-age=3600
複製代碼
表明這個響應返回後在 3600 秒,也就是一個小時以內能夠直接使用緩存。它其實能夠組合很是多的指令,完成更多場景的緩存判斷, 將一些關鍵的屬性列舉以下:
public: 客戶端和代理服務器均可以緩存。由於一個請求可能要通過不一樣的代理服務器
最後纔到達目標服務器,那麼結果就是不只僅瀏覽器能夠緩存數據,中間的任何代理節點均可以進行緩存。
private: 這種狀況就是隻有瀏覽器能緩存了,中間的代理服務器不能緩存。
no-cache: 跳過當前的強緩存,發送HTTP請求,即直接進入協商緩存階段
。
no-store:很是粗暴,不進行任何形式的緩存。
s-maxage:這和max-age
長得比較像,可是區別在於s-maxage是針對代理服務器的緩存時間。
must-revalidate: 是緩存就會有過時的時候,加上這個字段一旦緩存過時,就必須回到源服務器驗證。
代碼測試:
server.js
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come', request.url)
if (request.url === '/') {
const html = fs.readFileSync('test.html', 'utf8')
response.writeHead(200, {
'Content-Type': 'text/html'
})
response.end(html)
}
if (request.url === '/script.js') {
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-Control': 'max-age=20'
})
response.end('console.log("script loaded")')
}
}).listen(8888)
console.log('server listening on 8888')
複製代碼
cache.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>測試緩存</title>
</head>
<body>
</body>
<script src="/script.js"></script>
</html>
複製代碼
執行server.js
能夠用命令node server.js
,在瀏覽器中的打開http://localhost:8888
當超過咱們設置的時間max-age=20
超過20s後,頁面又會像咱們第一次打開時同樣。
二、協商緩存
當資源緩存時間超時了,也就是強緩存
失效了 ,就進入協商緩存了。
強緩存失效以後,瀏覽器在請求頭中攜帶相應的緩存tag
來向服務器發請求,由服務器根據這個tag,來決定是否使用緩存。 這樣的緩存tag分爲兩種: Last-Modified 和 ETag。
Last-Modified
Last-Modified:響應頭,即最後修改時間。在瀏覽器第一次給服務器發送請求後,服務器會在響應頭中加上這個字段。
瀏覽器接收到後,若是再次請求,會在請求頭中攜帶If-Modified-Since
字段,這個字段的值也就是服務器傳來的最後修改時間。
If-Modified-Since
: 請求頭,資源最近修改時間,由瀏覽器告訴服務器。
服務器拿到請求頭中的If-Modified-Since
的字段後,其實會和這個服務器中該資源的最後修改時間
對比:
ETag
ETag:響應頭,資源標識,由服務器告訴瀏覽器。
ETag
是服務器根據當前文件的內容,給文件生成的惟一標識,只要裏面的內容有改動,這個值就會變。服務器經過響應頭
把這個值給瀏覽器。
瀏覽器接收到ETag
的值,會在下次請求時,將這個值做爲If-None-Match這個字段的內容,並放到請求頭中,而後發給服務器。
If-None-Match: 請求頭,緩存資源標識,由瀏覽器告訴服務器。
服務器接收到If-None-Match後,會跟服務器上該資源的ETag進行比對:
304
,告訴瀏覽器直接用緩存。二者對比
精準度
上,ETag
優於Last-Modified
。優於 ETag 是按照內容給資源上標識,所以能準確感知資源的變化。而 Last-Modified 就不同了,它在一些特殊的狀況並不能準確感知資源變化,主要有兩種狀況:
Last-Modified
優於ETag
,也很簡單理解,Last-Modified
僅僅只是記錄一個時間點,而 Etag
須要根據文件的具體內容生成哈希值。另外,若是兩種方式都支持的話,服務器會優先考慮ETag
。
Last-Modified
存在問題
最後修改時間
, 這樣就沒法經過最後修改時間來判斷文件是否更新了。精確到秒
。內容並未改變
。 咱們不但願客戶端認爲這個文件修改了。CDN
服務器上的時候內容雖然同樣,修改時間不同。代碼測試
咱們添加協商緩存:
server.js
const http = require('http')
const fs = require('fs')
http.createServer(function (request, response) {
console.log('request come', request.url)
if (request.url === '/') {
const html = fs.readFileSync('test.html', 'utf8')
response.writeHead(200, {
'Content-Type': 'text/html'
})
response.end(html)
}
if (request.url === '/script.js') {
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-Control': 'max-age=20000000,no-cache',
'Last-Modified':'123',
'Etag':'666'
})
response.end('console.log("script loaded")')
}
}).listen(8888)
console.log('server listening on 8888')
複製代碼
從新啓動服務node server.js
,打開瀏覽器http://localhost:8888/
;
咱們發現,雖然設置了max-age='20000000'
,可是刷新頁面的時候,仍是發送了請求,沒有走緩存,由於還設置了no-cache
,會進入協商緩存,咱們設置了Etag
和Last-Modified
,在第二次刷新頁面的時候,請求頭增長了If-None-Match
和If-Modified-Since
且值跟Etag
和Last-Modified
相對應;
http/1.x中瀏覽器沒法主動得知服務器上的靜態資源變化沒有,且 Expires
或 Cache-Control
,他們都只可以控制緩存是否過時,可是在緩存過時以前,瀏覽器也是沒法得知服務器上的資源是否變化的。只有當緩存過時後,瀏覽器纔會發請求詢問服務器。 那麼這個時間(緩存沒有過時的時間)咱們上線了更改的靜態資源,瀏覽器仍是訪問緩存的舊的資源,怎麼解決呢?
解決方案:就是每次上線時,給靜態資源文件名命名不同;
通常個人處理方式是:
step1:咱們不讓 html 文件緩存,每次訪問 html 都去請求服務器。因此瀏覽器每次都能拿到最新的html資源。 step2:將原來的文件名加上每次打包的版本號,或者時間戳、指紋(不要產生新文件, < script src="/script.js?_h=1.6wee1" > )、加哈希(),這樣的好處是,能夠知道靜態資源時哪次打包的,哪些資源時此次更改的,若是出現錯誤,須要回溯版本,也能夠快速回溯。
簡單案例部分代碼:
第一次時:咱們在html使用的script.js
<script src="http://www.localhost:8888/script.js?version=1.0.1"></script>
複製代碼
ps: 瀏覽器下載1.0.1版本的script.js
文件。 瀏覽器再次訪問 html,發現仍是1.0.1版本的script.js
文件,則使用本地緩存。
某天咱們須要更改script.js
, 咱們的html文件也相應變化以下:
<script src="http://www.localhost:8888/script.js?version=1.0.2"></script>
複製代碼
ps: 經過設置html不緩存,html引用資源內容變化則改變資源路徑的方式,就解決了沒法及時得知資源更新的問題。
其實這仍是須要優化,爲何呢? 好比:頁面引用了3個css,a.css、b.css、c.css;而某次上線只改了其中的a.css,若是全部連接都更新版本,就會致使b.css,c.css的緩存也失效,那豈不是又有浪費了?!那怎麼辦呢? 有人想到了將文件名和url聯繫起來,使用數據摘要要算法 對文件求摘要信息,摘要信息與文件內容一一對應,就有了一種能夠精確到單個文件粒度的緩存控制依據了。可是這在大公司的項目中也是不能夠的,不是最優的。 爲了進一步提高網站性能,會把靜態資源和動態網頁分集羣部署,靜態資源會被部署到CDN節點上,好比七牛或者本身公司的CND上,這時候是否是你們都有一個問號了?對靜態資源和html放在不一樣的服務器了,那該先上線哪一個呢???好難!!! 訪問量不大的項目,可讓研發同窗苦逼一把,等到半夜偷偷上線,先上靜態資源,再部署頁面,看起來問題少一些。
大公司的靜態資源優化方案,基本上要實現這麼幾個東西:
另外,使用webpack打包的話,藉助插件能夠很方便的處理,使用哈希。
在HTTP協議中,內容協商是這樣一種機制,經過爲同一URL指向的資源提供不一樣的展示形式,能夠使用戶代理選擇與用戶需求相適應的最佳匹配(例如: 文檔使用的天然語言,圖片的格式,文件格式,json、表單、或則內容編碼形式)
當一項資源被訪問的時候,特定展示形式的選取是經過內容協商機制來決定的,而且客戶端和服務端之間存在多種協商方式。
請求聲明Accept:
Accept: 聲明我想要怎麼樣的數據,聲明數據類型
Accept-Encoding: 表明數據是怎麼樣的編碼方式,能夠使用壓縮
Accept-Language: 判斷返回的信息是什麼語言
User-Agent: 表示瀏覽器的一些相關的信息
複製代碼
與之對應的就是服務端Content:
Content-Type: 對應Accept,Accept能夠接收不少種數據格式,Content-Type會在裏面選擇一種數據格式返回,在返回的時候聲明返回的數據格式
Content-Encoding: 對應Accept-Encoding,告訴客戶端,我究竟用了什麼樣的壓縮數據的方式
Content-Language: 是否根據請求返回對應的語言
複製代碼
代碼測試:
server.js
const http = require('http')
const fs = require('fs')
const zlib = require('zlib') // 引入包
http.createServer(function (request, response) {
console.log('request come', request.url)
const html = fs.readFileSync('test.html') // 這裏不加 utf8,加了返回的就是字符串格式了
response.writeHead(200, {
'Content-Type': 'text/html',
// 'X-Content-Options': 'nosniff'
'Content-Encoding': 'gzip'
})
response.end(zlib.gzipSync(html)) // 壓縮
}).listen(8888)
console.log('server listening on 8888')
複製代碼
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="/form" id="form" enctype="application/x-www-form-urlencoded">
<input type="text" name="name">
<input type="password" name="password">
<input type="submit">
</form>
</body>
</html>
複製代碼
執行server.js
能夠用命令node server.js
,在瀏覽器中的打開http://localhost:8888
將test.html中form提交方式改成POST
<form action="/form" method="POST" id="form" enctype="application/x-www-form-urlencoded">
複製代碼
服務端根據 content-type 是 application/x-www-form-urlencoded來對body 中的數據進行轉化便可
在刷新瀏覽器,填寫表單內容,提交
增長文件的傳輸, 經過表單上傳文件時,必需要把文件部分單獨拆分出來,文件不能做爲字符串進行傳輸的,要做爲二進制的數據進行傳輸; multipart/form-data
test.html更改:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="/form" method="POST" id="form" enctype="multipart/form-data">
<input type="text" name="name">
<input type="password" name="password">
<input type="file" name="file">
<input type="submit">
</form>
<script>
var form = document.getElementById('form')
form.addEventListener('submit', function (e) {
e.preventDefault()
var formData = new FormData(form)
fetch('/form', {
method: 'POST',
body: formData
})
})
</script>
</body>
</html>
複製代碼
提交文件格式咱們表單的格式爲:enctype="multipart/form-data"
瀏覽器中抓包的請求頭中Content-Type
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarydHvHzymplSP4CAMk
複製代碼
請求體爲:
------WebKitFormBoundarydHvHzymplSP4CAMk
Content-Disposition: form-data; name="name"
111
------WebKitFormBoundarydHvHzymplSP4CAMk
Content-Disposition: form-data; name="password"
222
------WebKitFormBoundarydHvHzymplSP4CAMk
Content-Disposition: form-data; name="file"; filename="16ba0ae535359e94.jpg"
Content-Type: image/jpeg
------WebKitFormBoundarydHvHzymplSP4CAMk--
複製代碼
boundary=----WebKitFormBoundarybwAbNlPF2bBcTLuA
用來分割表單提交數據的各個部分
服務端拿到表單數據後,根據這個分割字符串,進行數據分割。
能夠使用zlib模塊進行壓縮及解壓縮處理,壓縮文件之後能夠減小體積,加快傳輸速度和節約帶寬
accept-encoding:gzip //開啓gzip
複製代碼
HTTP 壓縮就是以縮⼩體積爲⽬的,對 HTTP 內容進⾏從新編碼的過程 Gzip 壓縮背後的原理,是在⼀個⽂本⽂件中找出⼀些重複出現的字符串、臨時替換它們,從⽽使整個⽂ 件變⼩。根據這個原理,⽂件中代碼的重複率越⾼,那麼壓縮的效率就越⾼,使⽤ Gzip 的收益也就越 ⼤。反之亦然。
基本上來講,Gzip都是服務器⼲的活,⽐如nginx
壓縮對象
壓縮和解壓縮對象都是一個可讀可寫流
代碼案例:
var zlib = require('zlib');
var fs = require('fs');
var http = require('http');
var request = http.get({
host: 'localhost',
path: '/index.html',
port: 9090,
headers: {
'accept-encoding': 'gzip,deflate'
}
})
request.on('response', function (response) {
var output = fs.createWriteStream('test.txt');
switch (response.headers['content-encoding']) {
case 'gzip':
response.pipe(zlib.createGunzip()).pipe(output);
break;
case 'deflate':
response.pipe(zlib.createInflate()).pipe(output);
break;
default:
response.pipe(output);
break;
}
});
request.end();
複製代碼
href (Hypertext Reference)指定網絡資源的位置,從而在當前元素或者當前文檔和由當前屬性定義的須要的錨點或資源之間定義一個連接或者關係。(目的不是爲了引用資源,而是爲了創建聯繫,讓當前標籤可以連接到目標地址。)
src source(縮寫),指向外部資源的位置,指向的內容將會應用到文檔中當前標籤所在位置。
href與src的區別
一、請求資源類型不一樣:href 指向網絡資源所在位置,創建和當前元素(錨點)或當前文檔(連接)之間的聯繫。在請求 src 資源時會將其指向的資源下載並應用到文檔中,好比 JavaScript 腳本,img 圖片;
二、做用結果不一樣:href 用於在當前文檔和引用資源之間確立聯繫;src 用於替換當前內容;
三、瀏覽器解析方式不一樣:當瀏覽器解析到src ,會**暫停其餘資源的下載和處理,**直到將該資源加載、編譯、執行完畢,圖片和框架等也如此,相似於將所指向資源應用到當前內容。這也是爲何建議把 js 腳本放在底部而不是頭部的緣由。
重定向, 在response Header中增長Location,responseCode能夠是3xx
原理:
在 HTTP 協議中,重定向操做由服務器經過發送特殊的響應(即 redirects)而觸發。HTTP 協議的重定向響應的狀態碼爲 3xx 。瀏覽器在接收到重定向響應的時候,會採用該響應提供的新的 URL ,並當即進行加載;大多數狀況下,除了會有一小部分性能損失以外,重定向操做對於用戶來講是不可見的。
不一樣類型的重定向映射能夠劃分爲三個類別:
優先級:
任何狀況下,只要有可能,就應該採用 HTTP 協議的重定向機制,而不要使用 `` 標籤。假如開發人員修改了 HTTP 重定向映射而忘記修改 HTML 頁面的重定向映射,那麼兩者就會不一致,最終結果或者出現無限循環,或者致使其餘噩夢的發生。
設定方法:
一、HTML重定向機制: 這種機制會使瀏覽器的回退按鈕失效:能夠返回含有這個頭部的頁面,可是又會當即跳轉。
<head>
<meta http-equiv="refresh" content="0;URL=http://www.a.com/" />
</head>
複製代碼
二、JavaScript設置重定向
window.location = "http://www.a.com/";
複製代碼
三、在服務器中響應
例如咱們在客服端發出一個請求
const http = require('http')
http.createServer(function (request, response) {
console.log('request come', request.url)
if (request.url === '/') {
response.writeHead(302, {
'Location': '/new'
})
response.end()
}
if (request.url === '/new') {
response.writeHead(200, {
'Content-Type': 'text/html',
})
response.end('<div>this is content</div>')
}
}).listen(8888)
console.log('server listening on 8888')
複製代碼
ps:使用 永久性重定向 要慎重,一旦使用,服務端更改路由設置,用戶若是不清理瀏覽器緩存,就會一直重定向。
通常的通訊流程:首先客戶端發送一個請求(request)給服務器,服務器在接收到這個請求後將生成一個響應(response)返回給客戶端。
一次HTTP操做稱爲一個事務,其工做過程可分爲四步:
1)首先客戶端與服務器須要創建鏈接。只要單擊某個超級連接,HTTP的工做開始。
2)創建鏈接後,客戶端發送一個請求給服務器,請求方式的格式爲:統一資源標識符(URL)、協議版本號,後邊是MIME信息包括請求修飾符、客戶端信息和可能的內容。
3)服務器接到請求後,給予相應的響應信息,其格式爲一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,後邊是MIME信息包括服務器信息、實體信息和可能的內容。
4)客戶端接收服務器所返回的信息經過瀏覽器顯示在用戶的顯示屏上,而後客戶端與服務器斷開鏈接。
若是在以上過程當中的某一步出現錯誤,那麼產生錯誤的信息將返回到客戶端,有顯示屏輸出。對於用戶來講,這些過程是由HTTP本身完成的,用戶只要用鼠標點擊,等待信息顯示就能夠了。
HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL/TLS層。其所用的端口號是443。
HTTPS = HTTP+TLS/SSL
複製代碼
https通訊的優勢:
HTTPS和HTTP的區別主要以下:
HTTPS 協議的主要功能基本都依賴於 TLS/SSL 協議,TLS/SSL 的功能實現主要依賴於三類基本算法:
散列函數 散列函數驗證信息的完整性
對稱加密:對稱加密算法採用協商的密鑰對數據加密,密鑰只有一個,加密解密爲同一個密碼,且加解密速度快,典型的對稱加密算法有DES、AES,RC5,3DES等;
對稱加密主要問題是共享祕鑰,除你的計算機(客戶端)知道另一臺計算機(服務器)的私鑰祕鑰,不然沒法對通訊流進行加密解密。解決這個問題的方案非對稱祕鑰。
非對稱加密:非對稱加密實現身份認證和密鑰協商,使用兩個祕鑰:公共祕鑰和私有祕鑰。私有祕鑰由一方密碼保存(通常是服務器保存),另外一方任何人均可以得到公共祕鑰。
這種密鑰成對出現(且根據公鑰沒法推知私鑰,根據私鑰也沒法推知公鑰),加密解密使用不一樣密鑰(公鑰加密須要私鑰解密,私鑰加密須要公鑰解密),相對對稱加密速度較慢,典型的非對稱加密算法有RSA、DSA等。
代碼案例:
一、對稱加密:
const crypto = require('crypto');
function encrypt(data, key, iv) {
let decipher = crypto.createCipheriv('aes-128-cbc', key, iv);
decipher.update(data);
return decipher.final('hex');
}
function decrypt(data, key, iv) {
let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
decipher.update(data, 'hex');
return decipher.final('utf8');
}
let key = '1234567890123456';
let iv = '1234567890123456';
let data = "hello";
let encrypted = encrypt(data, key, iv);
console.log("數據加密後:", encrypted);
let decrypted = decrypt(encrypted, key, iv);
console.log("數據解密後:", decrypted);
複製代碼
二、非對稱加密:
let { generateKeyPairSync, privateEncrypt, publicDecrypt } = require('crypto');
let rsa = generateKeyPairSync('rsa', {
modulusLength: 1024,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'server_passphrase'
}
});
let message = 'hello';
let enc_by_prv = privateEncrypt({
key: rsa.privateKey, passphrase: 'server_passphrase'
}, Buffer.from(message, 'utf8'));
console.log('encrypted by private key: ' + enc_by_prv.toString('hex'));
let dec_by_pub = publicDecrypt(rsa.publicKey, enc_by_prv);
console.log('decrypted by public key: ' + dec_by_pub.toString('utf8'));
複製代碼
使用md5加密:
var crypto = require('crypto');
var content = '123456';
var result = crypto.createHash('md5').update(content).digest("hex")
console.log(result);//32位十六進制 = 128位二進制
複製代碼
sha256加密:
const salt = '123456';
const sha256 = str => crypto.createHmac('sha256', salt)
.update(str, 'utf8')
.digest('hex')
let ret = sha256(content);
console.log(ret);//64位十六進制 = 256位二進制
複製代碼
HTTPS 過程大體以下:
1) SSL客戶端經過TCP和服務器創建鏈接以後(443端口),而且在通常的tcp鏈接協商(握手)過程當中請求證書。
即客戶端發出一個消息給服務器,這個消息裏面包含了本身可實現的算法列表和其它一些須要的消息,SSL的服務器端會迴應一個數據包,這裏面肯定了此次通訊所須要的算法,而後服務器向客戶端返回證書。(證書裏面包含了服務器信息:域名。申請證書的公司,公共祕鑰)。
2)Client在收到服務器返回的證書後,判斷簽發這個證書的公共簽發機構,並使用這個機構的公共祕鑰確認簽名是否有效,客戶端還會確保證書中列出的域名就是它正在鏈接的域名。
3) 若是確認證書有效,那麼生成對稱祕鑰並使用服務器的公共祕鑰進行加密。而後發送給服務器,服務器使用它的私鑰對它進行解密,這樣兩臺計算機能夠開始進行對稱加密進行通訊。
ps:
SSL:安全套接層,是netscape公司設計的主要用於web的安全傳輸協議。這種協議在WEB上得到了普遍的應用。經過證書認證來確保客戶端和網站服務器之間的通訊數據是加密安全的。
傳輸層安全性協議(Transport Layer Security,縮寫TLS) 。
當一個資源從與該資源自己所在的服務器不一樣的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。 跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器 讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不一樣源服務器上的指定的資源。
內容安全策略 (CSP, Content Security Policy) 是一個附加的安全層,用於幫助檢測和緩解某些類型的攻擊,包括跨站腳本 (XSS) 和數據注入等攻擊。 這些攻擊可用於實現從數據竊取到網站破壞或做爲惡意軟件分發版本等用途。
語法格式:
Content-Security-Policy: default-src 'self'; img-src 'self' data:; media-src mediastream:
複製代碼
支持的策略指令:
一、 default-src
default-src
指令定義了那些沒有被更精確指令指定的(默認)安全策略。該指令包含了如下指令:
child-src
connect-src
font-src
img-src
:media-src
object-src
script-src
style-src
內容源:
內容源有三種:源列表、關鍵字和數據
關鍵字:
'none' 表明空集;即不匹配任何 URL。兩側單引號是必須的。
'self' 表明和文檔同源,包括相同的 URL 協議和端口號。兩側單引號是必須的。
'unsafe-inline' 容許使用內聯資源,如內聯的<script>
元素、javascript: URL、內聯的事件處理函數和內聯的<style>
元素,兩側單引號是必須的。
'unsafe-eval' 容許使用 eval() 等經過字符串建立代碼的方法。兩側單引號是必須的。
代碼例子
網站管理員但願全部內容都來自網站自己(不包括子域名)。
Content-Security-Policy: default-src 'self'
複製代碼
網站管理員但願容許來自受信任域及其全部子域的內容(它沒必要與CSP設置的域相同)。
Content-Security-Policy: default-src 'self' *.a.com
複製代碼
網站管理員但願容許Web應用程序的用戶未來自任何來源的圖像包含在本身的內容中,但要將音頻或視頻媒體限制爲可信任的提供者,而且僅將全部腳本限制在承載受信任代碼的特定服務器上。
Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com
複製代碼
在此,默認狀況下,僅容許來自文檔來源的內容,但如下狀況除外:
圖像可能從任何地方加載(請注意「*」通配符)。
媒體只容許來自media1.com和media2.com(而不是來自這些網站的子域)。
可執行腳本只容許來自userscripts.example.com。
更多內容可參考: developer.mozilla.org/zh-CN/docs/…
防護這些劫持最好的方法仍是從後端入手,前端能作的實在太少。並且因爲源碼的暴露,攻擊者很容易繞過咱們的防護手段。可是這不表明咱們去了解這塊的相關知識是沒意義的,本文的許多方法,用在其餘方面也是大有做用。
HTTP爲何不安全?有什麼缺點?
通訊使用明文(不加密),內容可能會被竊聽
不驗證通訊方身份,所以有可能遭遇假裝
沒法證實報文的完整性,因此有可能已遭篡改
一、可能被竊聽
二、 認證問題
三、 可能被篡改
請求或響應在傳輸途中,遭攻擊者攔截並篡改內容的攻擊被稱爲中間人攻擊(Man-in-the-Middle attack,MITM)。
HTTPS解決上述三個問題
HTTPS基於HTTP協議,經過SSL或TLS(能夠看做SSL3.0)提供加密處理數據、驗證對方身份以及數據完整性保護。特色以下:
HTTP協議Content Lenth限制漏洞致使拒絕服務攻擊
使用POST方法時,能夠設置ContentLenth來定義須要傳送的數據長度,例如ContentLenth:999999999,在傳送完成前,內 存不會釋放,攻擊者能夠利用這個缺陷,連續向WEB服務器發送垃圾數據直至WEB服務器內存耗盡。這種攻擊方法基本不會留下痕跡。
利用HTTP協議的特性進行拒絕服務攻擊的一些構思
服務器端忙於處理攻擊者僞造的TCP鏈接請求而無暇理睬客戶的正常請求(畢竟客戶端的正常請求比率很是之小),此時從正常客戶的角度看來,服務器失去響應,這種狀況咱們稱做:服務器端受到了SYNFlood攻擊(SYN洪水攻擊)。
而Smurf、TearDrop等是利用ICMP報文來Flood和IP碎片攻擊的。本文用「正常鏈接」的方法來產生拒絕服務攻擊。
19端口在早期已經有人用來作Chargen攻擊了,即Chargen_Denial_of_Service,可是!他們用的方法是在兩臺Chargen 服務器之間產生UDP鏈接,讓服務器處理過多信息而DOWN掉,那麼,幹掉一臺WEB服務器的條件就必須有2個:1.有Chargen服務2.有HTTP 服務
方法:攻擊者僞造源IP給N臺Chargen發送鏈接請求(Connect),Chargen接收到鏈接後就會返回每秒72字節的字符流(實際上根據網絡實際狀況,這個速度更快)給服務器。
HTTP頭注入
替換HTTP頭字符值中的換行符。
CSRF中文名爲跨站請求僞造。假如http://a.com
網址上有個加關注的GET接口,id參數是關注人Id,以下:
http://a.com?id=12
複製代碼
那我只須要在個人一個頁面裏面寫一個img標籤:
<img src="http://a.com?id=12" />
複製代碼
那麼只要有已經登陸http://a.com
網址的用戶打開我這個頁面,就會自動關注我。 就算是改成POST請求,也能夠經過在頁面使用form表單提交的方式自動關注。 CSRF攻擊是源於Web的隱式身份驗證機制!Web的身份驗證機制雖然能夠保證一個請求是來自於某個用戶的瀏覽器,但卻沒法保證該請求是用戶批准發送的。CSRF攻擊的問題通常是由服務端解決,防範 CSRF 攻擊能夠遵循如下幾種規則:
HTTP Only
一、驗證碼, 驗證碼被認爲是對抗 CSRF 攻擊最簡潔而有效的防護方法。
二、Referer Check, 根據 HTTP 協議,在 HTTP 頭中有一個字段叫 Referer,它記錄了該 HTTP 請求的來源地址。經過 Referer Check,能夠檢查請求是否來自合法的"源"。 Referer Check 不只能防範 CSRF 攻擊,另外一個應用場景是 "防止圖片盜鏈"。
咱們能夠建立一個白名單記錄咱們的請求網址,當瀏覽器器發出請求的referer
不在這個白名單內的網址,就認爲是收到了csrf攻擊,是不合法的請求,要拒絕該請求。
服務端代碼:
if (req.headers.referer !== 'http://www.c.com:8002/') {
res.write('csrf 攻擊');
return;
}
複製代碼
三、添加 token 驗證
要抵禦 CSRF,關鍵在於在請求中放入攻擊者所不能僞造的信息,而且該信息不存在於 Cookie 之中。能夠在 HTTP 請求中以參數的形式加入一個隨機產生的 token,並在服務器端創建一個攔截器來驗證這個 token,若是請求中沒有 token 或者 token 內容不正確,則認爲多是 CSRF 攻擊而拒絕該請求。
XSS跨站腳本
(Cross-site scripting) ,指的是攻擊者利用漏洞,向 Web 頁面中注入惡意代碼,當用戶瀏覽該頁之時,注入的代碼會被執行,從而達到攻擊的特殊目的。
XSS攻擊能夠分爲3類:反射型(非持久型)、存儲型(持久型)、基於DOM。
<a href="javascript:alert(1)"></a>
複製代碼
<iframe src="javascript:alert(1)" />
複製代碼
<img src='x' onerror="alert(1)" />
複製代碼
<video src='x' onerror="alert(1)" ></video>
複製代碼
<div onclick="alert(1)" onmouseover="alert(2)" ><div>
複製代碼
如今主流的瀏覽器內置了防範 XSS 的措施,例如 CSP。但對於開發者來講,也應該尋找可靠的解決方案來防止 XSS 攻擊。
一、HttpOnly 防止劫取 Cookie:
response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")
複製代碼
二、輸入檢查,由於用戶可能輸入的內容就是注入的腳本,當保存到服務器後,在返顯示到頁面就會被執行以前用戶輸入的注入內容;
解決方案: 對於用戶的任何輸入要進行檢查、過濾和轉義。創建可信任的字符和 HTML 標籤白名單,對於不在白名單之列的字符或者標籤進行過濾或編碼。
在 XSS 防護中,輸入檢查通常是檢查用戶輸入的數據中是否包含 <
,>
等特殊字符,若是存在,則對特殊字符進行過濾或編碼,這種方式也稱爲 XSS Filter。
// 在 vuejs 中,若是輸入帶 script 標籤的內容,會直接過濾掉
const decodingMap = {
'<': '<',
'>': '>',
'"': '"',
'&': '&',
' ': '\n'
}
複製代碼
三、輸出檢查, 服務端的輸出也會存在問題。通常來講,除富文本的輸出外,在變量輸出到 HTML 頁面時,能夠使用編碼或轉義的方式來防護 XSS 攻擊。例如利用 sanitize-html 對輸出內容進行有規則的過濾以後再輸出到頁面中。
防範:
一、文件上傳目錄設置成不可執行
二、判斷文件類型。結合MIME type與文件擴展名,設置文件類型白名單。對於圖片文件,能夠利用圖片庫函數深層次檢查是否真是圖片。
三、重命名文件名。
四、文件服務器使用獨立的域名。
防範:數據與代碼分離,即不用字符串拼湊SQL語句,使用SQL預處理方法(參數使用佔位符 ?)。
XST(跨站追蹤)攻擊,防範:關閉Web 服務器的TRACE方法。
第三次握手的緣由是爲了防止已失效的鏈接請求報文段忽然又傳回給服務器進程從而產生錯誤。假設客戶端發送第一次鏈接請求因爲網絡滯留了,因而客戶端又發送了一次請求併成功創建鏈接,數據傳輸完畢後就釋放了鏈接。在釋放鏈接後的某個時間段內客戶端的第一次報文段又到達了服務器並被服務器進程確認,若是沒有第三次握手,則服務器會一直等待客戶端發送數據,從而浪費許多資源。
可參考:how browers work
一、用戶輸入URL;
二、 瀏覽器首先依次查詢自身緩存,系統緩存和路由器緩存的記錄,若是沒有則查詢本地host文件,尚未就向DNS服務器發送域名解析請求;
三、瀏覽器向 DNS 服務器請求解析該 URL 中的域名所對應的 IP 地址;
四、解析出 IP 地址後,根據該 IP 地址和默認端口 80(若是輸入的URL中有端口號就用你輸入的), 向服務器指定端口發起TCP鏈接請求,經過運輸層,網絡層,數據鏈路層,物理層到達服務器,通過三次握手後創建TCP鏈接 ;
五、三次握手後,就能夠傳輸數據了,客戶端將要發送的內容構建成HTTP請求報文並封裝在TCP包中,經過TCP協議發送到服務器指定端口;
六、 服務器解析HTTP請求並按照報文格式封裝成須要的HTTP對象,返回給瀏覽器。
七、數據傳輸完畢後,就經過四次分手將客戶端和服務器的鏈接釋放。
八、 瀏覽器根據拿到的響應報文進行頁面的解析和渲染
ps:瀏覽器解析和渲染
瀏覽器根據拿到的響應報文進行解析和頁面的渲染。 在渲染頁面以前,須要構建DOM樹和CSSOM樹。 瀏覽器是一個邊解析邊渲染的過程。
一、構建DOM樹
HTML文檔會被解析成一棵以document爲根的DOM樹,解析過程當中若是遇到JavaScript,則會暫停解析並傳輸下載相應的文件形成阻塞,故推薦將JavaScript腳本放在HTML文件的後面。
二、構建CSSSOM樹
瀏覽器根據外部樣式,內部樣式和內聯樣式來解析CSS,構建CSSSOM樹。
三、構建渲染樹和佈局
DOM樹和CSSOM樹構建完畢後會融合成渲染樹,而後瀏覽器會確認頁面各元素的位置。
四、頁面繪製和優化
瀏覽器根據佈局結果進行頁面的繪製,並優化頁面內容,減少CPU消耗。
渲染結束後整個頁面就呈如今咱們面前了。
一、WebSocket:由於websokect是全雙工通訊,因此能夠實現多個標籤頁以前的通訊;
二、SharedWorker: html5瀏覽器的新特性, 能夠多個標籤頁、iframe共同使用的 三、 localstorage:是瀏覽器多個標籤共用的存儲空間,因此能夠用來實現多標籤之間的通訊;
思路: onstorage以及storage事件,針對都是非當前頁面對localStorage進行修改時纔會觸發,當前頁面修改localStorage不會觸發監聽函數。
window.onstorage = (e) => {console.log(e)}
複製代碼
或者
window.addEventListener("storage",function(event){
 $("#name").val(event.key+」=」+event.newValue);
});
複製代碼
注意quirks:Safari 在無痕模式下設置localstorge值時會拋出 QuotaExceededError 的異常
四、 使用cookie+setInterval
這個方法使用定時器不斷栓下,是至關浪費資源的,雖然能實現方案,可是不夠優雅。
思路:
在頁面A設置一個使用 setInterval 定時器不斷刷新,檢查 Cookies 的值是否發生變化,若是變化就進行刷新的操做。
因爲 Cookies 是在同域可讀的,因此在頁面 B 審覈的時候改變 Cookies 的值,頁面 A 天然是能夠拿到的。
TCP提供面向鏈接的,可靠的數據傳輸服務。以報文段的形式傳輸;
UDP提供無鏈接的,盡最大努力的數據傳輸服務。以用戶數據報的形式傳輸。
TCP與UDP的區別: TCP協議相對於UDP協議的特色是:TCP協議提供面向鏈接、字節流和可靠的傳輸。
常見狀態碼
200 - OK 請求成功,客戶端發過來的數據被正常處理
204 - Not Content 正常響應,沒有實體
206 - Partial Content 範圍請求,返回部分數據,響應報文中由Content-Range指定實體內容
301 - Moved Permanently 請求永久重定向,轉移到其它URL
302 - Found 請求臨時重定向
303 - See Other 和302相似,但必須用GET方法
304 - Not Modified) 狀態未改變, 配合(If-Match、If-Modified-Since、If-None_Match、If-Range、If-Unmodified-Since)
307 - Temporary Redirect 臨時重定向,和302相似,不應改變原請求方法
400 - Bad Request 客戶端請求報文存在語法錯誤
401 - unauthorized 客戶端請求沒有通過受權
403 - Forbidden 客戶端的請求被服務器拒絕,通常爲客戶端沒有訪問權限
404 - Not Found 服務器上沒法找到請求的資源
500 - Internal Server Error 服務器內部錯誤
503 - Service Unavailable 服務器處於超負載或正在停機維護
複製代碼
一、地址解析
二、封裝HTTP請求數據包
三、封裝TCP包,創建TCP連接(TCP的三次握手)
四、客戶端發送請求命令
五、服務器響應
六、服務器關閉TCP連接
長鏈接也能夠成爲持久連接,HTTP/1.1默認開啓長鏈接(持久連接), 數據傳輸完成了保持TCP鏈接不斷開(不發RST包、不四次握手),等待在同域名下繼續用這個通道傳輸數據(一個TCP鏈接上能夠傳送多個HTTP請求和響應);
爲何須要長鏈接?
TCP鏈接的新建成本很高,由於須要客戶端和服務器三次握手,而且開始時發送速率較慢(slow start)。 隨着網頁加載的外部資源愈來愈多,這個問題就愈發突出了。
因此, HTTP 1.0版本的性能比較差。 解決方法:在發送請求時,設置字段:
Connection: keep-alive
複製代碼
這個字段要求服務器不要關閉TCP鏈接,以便其餘請求複用。服務器一樣迴應這個字段。 一個能夠複用的TCP鏈接就創建了,直到客戶端或服務器主動關閉鏈接。可是,這不是標準字段,不一樣實現的行爲可能不一致,所以不是根本的解決辦法。
而HTTP/1.1默認開啓的, 不用聲明Connection: keep-alive
。
在 HTTP/2 中,四大特性:頭部壓縮、二進制流、服務器推送、多路複用。
爲何說HTTP /2 的信道複用能提升性能呢?
HTTP/2
了,模塊就能夠單獨的壓縮上線,而不影響其餘沒有修改的模塊。HTTP/2
以後,根據上面講的原理,咱們就不用這麼搞了,成本會更低。若是一個網站要全站由 HTTP 替換成 HTTPS,可能須要關注如下幾點:
緩存HTTP的倉庫,使經常使用頁面的副本能夠保存在離客戶端更近的地方。
HTTP的緩存分爲強緩存和協商緩存(對比緩存)。
HTTP緩存有多種規則,根據是否須要從新向服務器發起請求來分類,可將其分爲強制緩存,對比緩存。
通常個人處理方式是:
step1:咱們不讓 html 文件緩存( 靜態資源(css、js 、image、audio等) ),每次訪問 html 都去請求服務器。因此瀏覽器每次都能拿到最新的html資源。
step2:將 靜態資源(css、js 、image、audio等)原來的文件名加上每次打包的版本號,或者時間戳、指紋,這樣的好處是,能夠知道靜態資源時哪次打包的,哪些資源時此次更改的,若是出現錯誤,須要回溯版本,也能夠快速回溯。其實這樣仍是不是最優的方法;
對於大公司的靜態資源優化方案是: 用文件的摘要信息來對資源文件進行重命名,把摘要信息放到資源文件發佈路徑中,這樣,內容有修改的資源就變成了一個新的文件發佈到線上,不會覆蓋已有的資源文件。上線過程當中,先全量部署靜態資源,再灰度部署頁面,整個問題就比較完美的解決了。
因此,大公司的靜態資源優化方案,基本上要實現這麼幾個東西:
配置超長時間的本地緩存 —— 節省帶寬,提升性能 採用內容摘要做爲緩存更新依據 —— 精確的緩存控制 靜態資源CDN部署 —— 優化網絡請求 更資源發佈路徑實現非覆蓋式發佈 —— 平滑升級
step3:先上線靜態資源,在上線html
咱們能夠利用webpack工程化工具解決。
HTTP針對大文件的傳輸場景,能夠使用範圍請求
來解決,客戶端將資源一部分一部分傳輸。
通常是:壓縮、分塊、範圍請求、多端數據的流程。
那範圍請求是怎麼處理的呢?
響應頭使用:Accept-Ranges
用來告知客戶端這邊是支持範圍請求的;
請求頭使用: Rang
來制定請求哪一部分。Range: bytes=x-y
bytes=x-y
表示範圍格式有:
服務器收到請求以後,首先驗證範圍是否合法,若是越界了那麼返回416
錯誤碼,不然讀取相應片斷,返回206
狀態碼。
同時,服務器須要添加Content-Range
字段,這個字段的格式根據請求頭中Range
字段的不一樣而有所差別。
對於單段數據
的請求,返回的響應以下:
HTTP/1.1 206 Partial Content
Content-Length: 10
Accept-Ranges: bytes
Content-Range: bytes 0-9/100
。。。
複製代碼
值得注意的是Content-Range
字段,0-9
表示請求的返回,100
表示資源的總大小,很好理解。
多段數據
接下來咱們看看多段請求的狀況。獲得的響應會是下面這個形式:
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=00000010101
Content-Length: 189
Connection: keep-alive
Accept-Ranges: bytes
--00000010101
Content-Type: text/plain
Content-Range: bytes 0-9/96
--00000010101
Content-Type: text/plain
Content-Range: bytes 20-29/96
eex jspy e
--00000010101--
複製代碼
這個時候出現了一個很是關鍵的字段Content-Type: multipart/byteranges;boundary=00000010101
,它表明了信息量是這樣的:
所以,在響應體中各段數據之間會由這裏指定的分隔符分開,並且在最後的分隔末尾添上--
表示結束。
代理是位於客戶端和服務器之間的HTTP中間實體。接收全部客戶端的HTTP請求,並將這些請求轉發給服務器(可能會對請求進行修改以後轉發)。
用戶Agent代理是表明用戶發起HTTP的客戶端程序。好比Web瀏覽器。另外有些自動發送HTTP請求並獲取內容的代理,好比「網絡蜘蛛」或者「Web機器人」。
在web中,http代理是一種客戶端和web服務器之間的一種實體。它既具有客戶端的發起請求功能,還能夠像web服務器同樣返回響應。
代理和網關之間的首要差別是代理只能轉發同一種協議,而網關可以轉發多種協議。
HTTP 代理存在兩種形式,分別簡單介紹以下:
第一種是 RFC 7230 - HTTP/1.1: Message Syntax and Routing(即修訂後的 RFC 2616,HTTP/1.1 協議的第一部分)描述的普通代理。這種代理扮演的是「中間人」角色,對於鏈接到它的客戶端來講,它是服務端;對於要鏈接的服務端來講,它是客戶端。它就負責在兩端之間來回傳送 HTTP 報文。
第二種是 Tunneling TCP based protocols through Web proxy servers(經過 Web 代理服務器用隧道方式傳輸基於 TCP 的協議)描述的隧道代理。它經過 HTTP 協議正文部分(Body)完成通信,以 HTTP 的方式實現任意基於 TCP 的應用層協議代理。這種代理使用 HTTP 的 CONNECT 方法創建鏈接,但 CONNECT 最開始並非 RFC 2616 - HTTP/1.1 的一部分,直到 2014 年發佈的 HTTP/1.1 修訂版中,才增長了對 CONNECT 及隧道代理的描述,詳見 RFC 7231 - HTTP/1.1: Semantics and Content。實際上這種代理早就被普遍實現。
網關是一種特殊的服務器,做爲其餘服務器的中間實體使用。一般用於將HTTP流量轉換成其餘的協議。
隧道是創建起來以後,就會在兩條鏈接之間對原始數據進行盲轉發的HTTP應用程序。常見用途是經過HTTP鏈接承載加密的安全套接字層(SSL)流量,這樣SSL流量就能夠穿過只容許Web流量經過的防火牆了。
———————————————————————————————————
本文解析或者答案僅供參考,內容參考如下資料~~
《圖解HTTP》
《HTTP權威指南》
cloud.tencent.com/document/pr…
ye11ow.gitbooks.io/http2-expla…