深刻理解HTTP協議,鞏固HTTP知識體系——長文,可收藏閱讀

前言

若是你是中高級的前端工程師,相關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簡述

web:(網頁瀏覽器web browser);

web頁面不會憑空顯示出來。根據Web瀏覽器地址欄中指定的URL,web瀏覽器從Web服務器獲取資源等信息,從而顯示出web頁面。web使用HTTP(超文本傳輸協議)的協議做爲規範,完成從客服端到服務器端等一系列運做流程。Web是簡歷在HTTP協議上的通訊。

協議:指定規則的約定;爲了讓計算機可以通訊,計算機須要定義通訊規則,這些規則就是協議;是數據封裝格式+傳輸 ;協議有多種;

客戶端:像這種經過發送請求獲取服務資源的web瀏覽器等,均可以稱爲客戶端(client)。

網絡基礎TCP/IP

爲了瞭解HTTP,咱們必須先了解TCP/IP協議族因一般使用的網絡(包括互聯網)是在TCP/IP協議族的基礎上運做的。而HTTP屬於它內部的一個子集。

TCP/IP

把與互聯網相關聯的協議集合起來總成爲TCP/IP。

也有認爲:TCP/IP是指TCP和IP這兩種協議。

還有認爲:TCP/IP是IP協議的通訊過程當中,使用到的協議族的統稱。

爲何分層?

  • 將複雜的流程分解爲幾個功能相對單一的子進程
  • 整個流程更加清晰,複雜問題簡單化
  • 更容易發現問題並針對性的解決問題

OSI七層網絡模型

分層 功能 做用
應用層 網絡服務於最終用戶的一個接口 提供網絡與用戶應用軟件之間的接口服務,屏蔽了網絡傳輸相關細節
表示層 數據的表示、安全、壓縮 提供格式化的表示和轉換數據服務,如加密和壓縮
會話層 創建、管理、停止會話 提供包括訪問驗證和會話管理在內的創建和維護應用之間通訊的機制
傳輸層 定義傳輸數據的協議端口號,以及留空和差錯校驗 一、提供創建、維護和取消傳輸鏈接功能,負責可靠地傳輸數據(PC);二、向用戶提供可靠的(端到端end-to-end)服務;三、傳輸層向高層屏蔽了下層數據通訊的細節
網絡層 進行邏輯地址尋址,實現不一樣網絡之間的路徑選擇 處理網絡間路由,確保數據及時傳送(路由器),數據包是網絡傳輸的最小數據單位。該層規定了經過怎樣的路徑(傳輸路線)到達對方計算機,並把數據包傳送給對方。
數據鏈路層 創建邏輯鏈接、進行硬件地址尋址、差錯校驗等功能 用來處理連接網絡的硬件部分。負責無錯傳輸數據,確認幀、發錯重傳等(交換機)
物理層 創建、維護、斷開物理鏈接 定義物理設備如何傳輸數據;提供機械、電氣、功能和過程特性(網卡、網線、雙絞線、同軸電纜、中繼器)

TCP/IP參考模型

網絡五層結構

  • TCP/IP是傳輸控制協議/網絡互聯協議的簡稱
  • 早期的TCP/IP模型是一個四層結構,從下往上依次是網絡接口層、互聯網層、傳輸層和應用層
  • 後來在使用過程當中,借鑑OSI七層參考模型,將網絡接口層劃分爲了物理層和數據鏈路層,造成五層結構
分層 協議
應用層 HTTP(超文本傳輸協議)、FTP(文件傳輸協議)、TFTP、SMTP(發送郵件)、SNMP、DNS(域名系統)。。。
傳輸層 TCP(傳輸控制協議)、UDP(用戶數據報協議)。。。
網絡層 ICMP(網際控制消息協議,發送消息,並報告有關數據包的傳送錯誤)、IGMP(互聯組管理協議,IP主機向本地多路廣播路由器報告主機組成員)、IP(網際協議,負責主機和網絡之間尋址和路由數據包)、ARP(地址解析協議,得到同一物理網絡中的硬件主機MAC地址)。。。
數據鏈路層 由底層網絡定義的協議
物理層 由底層網絡定義的協議

數據包封裝

上層協議數據是如何轉變爲下層協議數據的呢?

這是經過封裝(encapsulate)來實現的。應用程序數據在發送到物理網絡以前,會沿着協議棧從上往下傳遞。每層協議都將在上層協議數據的基礎上加上本身的頭部信息(鏈路層還會加上尾部信息),覺得實現該層功能提供必要的信息。 發送端發送數據時,數據會從上層傳輸到下層,且每通過一層都會被打上該層的頭部信息。而接收端接收數據時,數據會從下層傳輸到上層,傳輸前會把下層的頭部信息刪除。

爲何要這樣封裝呢?

因爲下層協議的頭部信息對上層協議是沒有實際的用途,因此在下層協議傳輸數據給上層協議的時候會把該層的頭部信息去掉,這個封裝過程對於上層協議來講是徹底透明的。這樣作的好處是,應用層只須要關心應用服務的實現,而不用管底層的實現。

與HTTP關係親密的協議:IP、TCP、DNS

一、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功能:

  • 鏈接創建 : 主要是指TCP/IP的三次握手來創建鏈接
  • 將數據進行分段打包傳輸: 主要是實在網絡傳輸過程當中的MTU(最大傳輸單元)決定的,數據必須打包成段才能夠傳送 ;
  • 對每一個數據包編號控制順序: 數據打包成段後,須要按序列號排序來發送,保證數據的連貫性
  • 運輸中丟失、重發和丟棄處理
  • 流量控制: 經過滑動窗口來進行流量的控制
  • 避免擁塞: 解決擁塞控制的辦法是:採用慢啓動和擁塞避免算法結合使用來控制擁塞

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協議

  • TCP(Transimision Control Protocal)
    • 傳輸控制協議
    • 可靠的、面向鏈接的協議
    • 傳輸效率低
  • UDP(User Datagram Protocal)
    • 用戶數據報協議
    • 不可靠的、無鏈接的服務
    • 傳輸效率高
  • TCP與UDP的區別:能夠看出 TCP協議相對於UDP協議的特色是:TCP協議提供面向鏈接、字節流和可靠的傳輸。

2.四、UDP的應用

  • QQ
  • 視頻軟件
  • TFTP 簡單文件傳輸協議(短信)

2.五、三次握手、數據傳輸、四次揮手

爲了防止服務器開啓無用的連接。

2.5.一、三次握手

爲了準確無誤地將數據傳送到目標處,TCP才用了三次握手策略。

注意:

  • TCP是面向鏈接的協議,它在源點和終點之間創建虛擬鏈接,而不是物理鏈接
  • 在數據通訊以前,發送端與接收端要先創建鏈接,等數據發送結束後,雙方再斷開鏈接
  • TCP鏈接的每一方都是由一個IP地址和一個端口組成
  • http是不存在鏈接這個概念的,只有請求和響應,他們都是數據包

具體過程以下:

**第一次握手:**客戶端發送帶有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.二、數據傳輸

  • 客戶端先向服務器發送數據,該數據報是長度爲159的數據。
  • 服務器收到報文後, 也向客戶端發送了一個數據進行確認(ACK),而且返回客戶端要請求的數據,數據的長度爲111,將seq設置爲1,ack設置爲160(1 + 159)。
  • 客戶端收到服務器返回的數據後進行確認(ACK),將seq設置爲160, ack設置爲112(1 + 111)。

2.5.三、四次斷開

  • 客戶端發送FIN控制位發出斷開鏈接的請求
  • 服務器進行響應,確認收到斷開鏈接請求
  • 服務器提出反方向的關閉要求
  • 客戶端確認收到的主機B的關閉鏈接請求

** 三、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:

  • Unix Domain: 基於socket機制實現同一主機不一樣進程間通訊的一種方式;AF_UNIX, AF_LOCAL,地址是一個路徑名(文件)
  • IPv4 Domain: AF_INET, 基於socket機制藉助於ipv4協議實現不一樣主機(也能夠是同一主機)上的進程間通訊的機制; 地址是32位的ipv4地址+16位的端口號
  • IPv6 Domain: AF_INET6, 地址是128位的Ipv6地址+16位的端口號

二、socket的類型:

  • TCP:流式socket,SOCK_STREAM 提供可靠、雙向、面向字節流
  • UDP:數據報式socket, SOCK_DGRAM

三、相關的系統調用:

  • socket( ): 建立一個新的socket
  • bind( ):綁定於一個套按字地址和端口上
  • listen( ): 監聽套接字
  • accept( ): 接收鏈接請求
  • connect( ): 發起鏈接請求
  • close( ): 關閉鏈接
  • read( ):從套接字向緩衝區讀入數據
  • write( ): 從緩存區向套接字中寫入數據

URL、URI

URI用字符串標識某一互聯網資源,而URL表示資源的地點(互聯網上所處的位置)。URL是URI的子集。

一、URI

URI(Uniform Resource Identifier)是統一資源標識符,在某個規則下能把這個資源獨一無二標示出來,好比人的身份證號。

  • Uniform:規定統一的格式客房部處理多種不一樣類型的資源,而不用根據上下文來識別資源指定的訪問方式;
  • Resource:能夠標識的任何東西
  • Identifier:表示可標識的對象

二、URL

URL(Uniform Resource Locator)統一資源定位符,表示資源的地點,URL正是使用瀏覽器訪問WEB頁面時須要輸入的網頁地址

  • Uniform 不用根據上下文來識別資源指定的訪問方式
  • Resource 能夠標識的任何東西
  • Location 定位

2.一、URL的格式

  • 協議類型:使用 http, https, file等協議方案名獲取訪問資源時要指定協議類型。也能夠使用data:或者javascript:這類指定數據或者腳本程序的方案名。不區分大小寫,最後附一個冒號。後面必須和://連在一塊兒。
  • 登陸信息:可選項。指定用戶名和密碼做爲從服務器端貨物資源時必要的登陸信息。 很不安全,不推薦使用,也不經常使用。
  • 服務器地址:服務器地址
  • 服務器端口號:服務器端口號
  • 帶層次的文件路徑: 表示請求路徑,標記資源所在位置。
  • 查詢字符串: 表示查詢參數,爲key=val這種形式,多個鍵值對之間用&隔開。
  • 片斷標識符: 表示 URI 所定位的資源內的一個錨點,瀏覽器能夠根據這個錨點跳轉到對應的位置

HTTP協議

HTTP簡介

  • HTTP是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫。
  • HTTP協議可以明確區分哪端是客戶端,哪端是服務器端。請求的一方叫客戶端,響應的一方叫服務器端。
  • 經過請求和響應的交換達成通訊
  • HTTP協議是用於從WWW服務器傳輸超文本到本地瀏覽器的傳送協議。它能夠使瀏覽器更加高效,使網絡傳輸減小。它不只保證計算機正確快速地傳輸超文本文檔,還肯定傳輸文檔中的哪一部分,以及哪部份內容首先顯示(如文本先於圖形)等。
  • HTTP是一個應用層的面向對象協議, 是一個基於TCP/IP通訊協議來傳遞數據(HTML 文件, 圖片文件, 查詢結果等)。
  • HTTP是一個無狀態的協議。
  • 默認HTTP的端口號爲80,HTTPS的端口號爲443。
  • HTTP協議一般承載於TCP協議之上,有時也承載於TLS或SSL協議層之上,這個時候,就成了咱們常說的HTTPS。以下圖:

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)中設定這個時間

HTTP版本

它的發展是萬維網協會(World Wide Web Consortium)和Internet工做小組IETF(Internet Engineering Task Force)合做的結果,(他們)最終發佈了一系列的RFC,RFC 1945定義了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定義了今天廣泛使用的一個版本——HTTP /1.1。

HTTP/0.9

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鏈接。

HTTP/1.0

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

HTTP/1.1:

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版還新增了許多動詞方法:PUTPATCHHEADOPTIONSDELETE

另外,客戶端請求的頭信息新增了Host字段,用來指定服務器的域名。

http/1.1缺點:

一、"隊頭堵塞"(Head-of-line blocking): 1.1版容許複用TCP鏈接,可是同一個TCP鏈接裏面,全部的數據通訊是按次序進行的。服務器只有處理完一個迴應,纔會進行下一個迴應。要是前面的迴應特別慢,後面就會有許多請求排隊等着。

解決方法:

  • 將同一頁面的資源分散到不一樣域名下,提高鏈接上限。 Chrome有個機制,對於同一個域名,默認容許同時創建 6 個 TCP持久鏈接,使用持久鏈接時,雖然能公用一個TCP管道,可是在一個管道中同一時刻只能處理一個請求,在當前的請求沒有結束以前,其餘的請求只能處於阻塞狀態。另外若是在同一個域名下同時有10個請求發生,那麼其中4個請求會進入排隊等待狀態,直至進行中的請求完成。
  • Spriting合併多張小圖爲一張大圖,再用JavaScript或者CSS將小圖從新「切割」出來的技術。
  • 內聯(Inlining)是另一種防止發送不少小圖請求的技巧,將圖片的原始數據嵌入在CSS文件裏面的URL裏,減小網絡請求次數。
  • 拼接(Concatenation)將多個體積較小的JavaScript使用webpack等工具打包成1個體積更大的JavaScript文件,但若是其中1個文件的改動就會致使大量數據被從新下載多個文件。

二、HTTP頭部巨大

三、明文傳輸--帶來的不安全性

四、服務器不能主動推送

**SPDY **

上面咱們提到,因爲HTTP/1.1的缺點,想解決的話,咱們會合並腳本和樣式表、雪碧圖、將圖片嵌入CSS代碼、域名分片(domain sharding)等等的方式來提升性能。不過這些優化都繞開了協議,直到2009年,谷歌公開了自行研發的 SPDY 協議,主要解決HTTP/1.1效率不高的問題。谷歌推出SPDY,纔算是正式改造HTTP協議自己。下降延遲,壓縮header等等,SPDY的實踐證實了這些優化的效果,也最終帶來HTTP/2的誕生。

HTTP/2:

簡介:

2015年,HTTP/2 發佈。它不叫 HTTP/2.0,是由於標準委員會不打算再發布子版本了,下一個新版本將是 HTTP/3。 全部數據以二進制傳輸、同一個鏈接裏面發送多個請求再也不須要按照順序來了、頭信息壓縮以及推送(服務端能夠主動發起請求了)等提升了效率的功能

  • HTTP/2是現行HTTP協議(HTTP/1.x)的替代,但它不是重寫;
  • HTTP方法/狀態碼/語義都與HTTP/1.x同樣。
  • HTTP/2基於SPDY,專一於性能,最大的一個目標是在用戶和網站間只用一個鏈接(connection)
  • 從目前的狀況來看,國內外一些排名靠前的站點基本都實現了HTTP/2的部署,使用HTTP/2能帶來20%~60%的效率提高。

HTTP/2由兩個規範(Specification)組成:

  1. Hypertext Transfer Protocol version 2 - RFC7540
  2. HPACK - Header Compression for HTTP/2 - RFC7541

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首部

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
複製代碼

固然還能夠使用其餘的抓包工具查看,在這就不一一列舉了。

HTTP請求方法:

注意方法名要大寫。

方法 說明 支持版本
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 請求會被瀏覽器主動緩存下來,留下歷史記錄,而 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 包)

HTTP狀態碼及含義

狀態碼的職責是當客戶端向服務器端發送請求時,描述返回的請求結果。藉助狀態碼,用戶能夠知道服務器端是正常處理請求,仍是出現了錯誤。

響應碼 含義、應用
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首部字段有首部字段名和首部字段值構成,中間用冒號:分割

通常有四種首部:通用首部、請求首部、響應首部和實體首部;

首部字段:

  • 字段名不區分大小寫

  • 字段名不容許出現空格,不能夠出現下劃線_

  • 字段名後面必須緊接着:

  • 字段值對應單個HTTP首部字段能夠有多個值

    Keep-Alive: timeout=15,max=100
    複製代碼

如下是HTTP\1.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 資源的最後修改時間

五、非HTTP/1.1首部字段

還有使用頻率比較高的首部字段有:CookieSetCookieContene-Disposition

六、End-to-end 首部和 Hop-by-hop 首部

HTTP 首部字段將定義成緩存代理和非緩存代理的行爲,分紅 2 種類型。

端到端首部(End-to-end): 分在此類別中的首部會轉發給請求 / 響應對應的最終接收目標,且必須保存在由緩存生成的響應中,另外規 定它必須被轉發。

逐跳首部(Hop-by-hop):分在此類別中的首部只對單次轉發有效,會因經過緩存或代理而再也不轉發。HTTP/1.1 和以後版本中,若是要使用 hop-by-hop 首部,需提供 Connection 首部字段。

下面列舉了 HTTP/1.1 中的逐跳首部字段。除這 8 個首部字段以外,其餘全部字段都屬於端到端首部。

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • Trailer
  • TE
  • Transfer-Encoding
  • Upgrade

常見的報文頭的屬性

字段 說明 示例
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的指令,就能操做緩存的工做機制。

語法格式:

指令的參數是可選的,多個指令之間經過','分隔。

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,用於定義網絡文件的類型和網頁的編碼,決定瀏覽器將以什麼形式、什麼編碼讀取這個文件。

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提交數據的方式。
中默認的encType,瀏覽器原生的form表單,若是不設置enctype屬性,那麼最終就會以 application/x-www-form-urlencoded 方式提交數據 。form表單數據被編碼爲key/value格式發送到服務器(表單默認的提交數據的格式)
application/octet-stream 二進制流數據(如常見的文件下載)

另一種常見的媒體格式是上傳文件之時使用的

媒體格式類型 說明
multipart/form-data 須要在表單中進行文件上傳時,就須要使用該格式

Cookie

管理服務器與客戶端之間狀態的 Cookie,雖然沒有被編入標準化 HTTP/1.1 的 RFC2616 中,但在 Web 網 站方面獲得了普遍的應用。 Cookie 的工做機制是用戶識別及狀態管理。Web 網站爲了管理用戶的狀態會經過 Web 瀏覽器,把一些數據 臨時寫入用戶的計算機內。接着當用戶訪問該Web網站時,可經過通訊方式取回以前發放的 Cookie。

爲 Cookie 服務的首部字段

首部字段名 說明 首部類型
Set-Cookie 開始狀態管理所使用的Cookie信息 響應首部字段
Cookie 服務器接收到的Cookie信息 請求首部字段

Cookie的處理流程:

一、 客戶端第一次訪問服務器的時候服務器經過響應頭向客戶端發送Cookie,屬性之間用分號空格分隔

二、 客戶端接收到Cookie以後保存在本地

三、 之後客戶端再請求服務器的時候會把此Cookie發送到服務器端

Set-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

Cookie: status=enable
複製代碼

首部字段 Cookie 會告知服務器,當客戶端想得到 HTTP 狀態管理支持時,就會在請求中包含從服務器接收到的 Cookie。接收到多個 Cookie 時,一樣能夠以多個 Cookie 形式發送。

Cookie使用注意事項:

  • 可能被客戶端篡改,使用前驗證合法性
  • 不要存儲敏感數據,好比用戶密碼,帳戶餘額
  • 使用httpOnly保證安全
  • 儘可能減小cookie的體積
  • 設置正確的domain和path,減小數據傳輸

session

session是另外一種記錄客戶狀態的機制,不一樣的是Cookie保存在客戶端瀏覽器中,而session保存在服務器上

客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上,這就是session。客戶端瀏覽器再次訪問時只須要從該Session中查找該客戶的狀態就能夠了

cookie與session區別

  1. cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
  2. cookie不是很安全,別人能夠分析存放在本地的COOKIE並進行COOKIE欺騙 考慮到安全應當使用session
  3. session會在必定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能 考慮到減輕服務器性能方面,應當使用COOKIE
  4. 單個cookie保存的數據不能超過4K,不少瀏覽器都限制一個站點最多保存20個cookie

將登錄信息等重要信息存放爲session、其餘信息若是須要保留,能夠放在cookie中

緩存

經過⽹絡獲取內容既速度緩慢⼜開銷巨⼤。較⼤的響應須要在客戶端與服務器之間進⾏屢次往返通訊,

這會延遲瀏覽器得到和處理內容的時間,還會增長訪問者的流量費⽤。所以,緩存並重複利⽤以前獲取

的資源的能⼒成爲性能優化的⼀個關鍵⽅⾯。

緩存做用

  • 減小了冗餘的數據傳輸,節省了網費。
  • 減小了服務器的負擔, 大大提升了網站的性能
  • 加快了客戶端加載網頁的速度

緩存分類

⼴義的緩存,能夠分爲這四個

    1. Http Cache
    1. Service Worker Cache:

      Service Worker 借鑑了 Web Worker的 思路,即讓 JS 運行在主線程以外,因爲它脫離了瀏覽器的窗體,所以沒法直接訪問DOM。雖然如此,但它仍然能幫助咱們完成不少有用的功能,好比離線緩存消息推送網絡代理等功能。其中的離線緩存就是 Service Worker Cache

    1. Memory Cache:

      內存緩存,從效率上講它是最快的。可是從存活時間來說又是最短的,當渲染進程結束後,內存緩存也就不存在了。

    1. Push Cache:(HTTP/2中的服務器推送)

HTTP緩存

HTTP緩存有多種規則,根據是否須要從新向服務器發起請求來分類,可將其分爲強制緩存,對比緩存。

  • 強制緩存若是生效,不須要再和服務器發生交互,而對比緩存無論是否生效,都須要與服務端發生交互
  • 兩類緩存規則能夠同時存在,強制緩存優先級高於對比緩存,也就是說,當執行強制緩存的規則時,若是緩存生效,直接使用緩存,再也不執行對比緩存規則

一、強緩存

瀏覽器中的緩存做用分爲兩種狀況,一種是須要發送HTTP請求,一種是不須要發送。

首先是檢查強緩存,這個階段不須要發送HTTP請求。

那麼瀏覽器是如何檢查的呢?

咱們知道,在沒有緩存數據的時候,瀏覽器向服務器請求數據時,服務器會將數據和緩存規則一併返回,緩存規則信息包含在響應header中。

注意:

HTTP/1.0HTTP/1.1當中,這個字段是不同的。在早期,也就是HTTP/1.0時期,使用的是Expires,而HTTP/1.1使用的是Cache-Control。當ExpiresCache-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後,頁面又會像咱們第一次打開時同樣。

二、協商緩存

當資源緩存時間超時了,也就是強緩存失效了 ,就進入協商緩存了。

  • 對比緩存,顧名思義,須要進行比較判斷是否能夠使用緩存。
  • 瀏覽器第一次請求數據時,服務器會將緩存標識與數據一塊兒返回給客戶端,客戶端將兩者備份至緩存數據庫中。
  • 再次請求數據時,客戶端將備份的緩存標識發送給服務器,服務器根據緩存標識進行判斷,判斷成功後,返回304狀態碼,通知客戶端比較成功,能夠使用緩存數據。

強緩存失效以後,瀏覽器在請求頭中攜帶相應的緩存tag來向服務器發請求,由服務器根據這個tag,來決定是否使用緩存。 這樣的緩存tag分爲兩種: Last-ModifiedETag

Last-Modified

Last-Modified:響應頭,即最後修改時間。在瀏覽器第一次給服務器發送請求後,服務器會在響應頭中加上這個字段。

瀏覽器接收到後,若是再次請求,會在請求頭中攜帶If-Modified-Since字段,這個字段的值也就是服務器傳來的最後修改時間。

If-Modified-Since: 請求頭,資源最近修改時間,由瀏覽器告訴服務器。

服務器拿到請求頭中的If-Modified-Since的字段後,其實會和這個服務器中該資源的最後修改時間對比:

  • 若是請求頭中的這個值小於最後修改時間,說明是時候更新了。返回新的資源,跟常規的HTTP請求響應的流程同樣。
  • 不然返回304,告訴瀏覽器直接用緩存。

ETag

ETag:響應頭,資源標識,由服務器告訴瀏覽器。

ETag 是服務器根據當前文件的內容,給文件生成的惟一標識,只要裏面的內容有改動,這個值就會變。服務器經過響應頭把這個值給瀏覽器。

瀏覽器接收到ETag的值,會在下次請求時,將這個值做爲If-None-Match這個字段的內容,並放到請求頭中,而後發給服務器。

If-None-Match: 請求頭,緩存資源標識,由瀏覽器告訴服務器。

服務器接收到If-None-Match後,會跟服務器上該資源的ETag進行比對:

  • 若是二者不同,說明要更新了。返回新的資源,跟常規的HTTP請求響應的流程同樣。
  • 不然返回304,告訴瀏覽器直接用緩存。

二者對比

  1. 精準度上,ETag優於Last-Modified。優於 ETag 是按照內容給資源上標識,所以能準確感知資源的變化。而 Last-Modified 就不同了,它在一些特殊的狀況並不能準確感知資源變化,主要有兩種狀況:
    • 編輯了資源文件,可是文件內容並無更改,這樣也會形成緩存失效。
    • Last-Modified 可以感知的單位時間是秒,若是文件在 1 秒內改變了屢次,那麼這時候的 Last-Modified 並無體現出修改了。
  2. 在性能上,Last-Modified優於ETag,也很簡單理解,Last-Modified僅僅只是記錄一個時間點,而 Etag須要根據文件的具體內容生成哈希值。

另外,若是兩種方式都支持的話,服務器會優先考慮ETag

Last-Modified存在問題

  1. 某些服務器不能精確獲得文件的最後修改時間, 這樣就沒法經過最後修改時間來判斷文件是否更新了。
  2. 某些文件的修改很是頻繁,在秒如下的時間內進行修改. Last-Modified只能精確到秒
  3. 一些文件的最後修改時間改變了,可是內容並未改變。 咱們不但願客戶端認爲這個文件修改了。
  4. 若是一樣的一個文件位於多個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,會進入協商緩存,咱們設置了EtagLast-Modified,在第二次刷新頁面的時候,請求頭增長了If-None-MatchIf-Modified-Since且值跟EtagLast-Modified相對應;

緩存致使的靜態資源等更改頁面不改變問題

http/1.x中瀏覽器沒法主動得知服務器上的靜態資源變化沒有,且 ExpiresCache-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放在不一樣的服務器了,那該先上線哪一個呢???好難!!! 訪問量不大的項目,可讓研發同窗苦逼一把,等到半夜偷偷上線,先上靜態資源,再部署頁面,看起來問題少一些。

大公司的靜態資源優化方案,基本上要實現這麼幾個東西:

  • 配置超長時間的本地緩存 —— 節省帶寬,提升性能
  • 採用內容摘要做爲緩存更新依據 —— 精確的緩存控制
  • 靜態資源CDN部署 —— 優化網絡請求
  • 更資源發佈路徑實現非覆蓋式發佈 —— 平滑升級

另外,使用webpack打包的話,藉助插件能夠很方便的處理,使用哈希。

緩存判斷順序

  • 一、先判斷Cache-Control,在Cache-Control的max-age以內,直接返回200 from cache;
  • 二、沒有Cache-Control再判斷Expires,再Expires以內,直接返回200 from cache;
  • 三、Cache-Control=no-cache或者不符合Expires,瀏覽器向服務器發送請求;
  • 四、服務器同時判斷ETag和Last-Modified,都一致,返回304,有任何一個不一致,返回200。

HTTP數據協商(內容協商)

在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

壓縮對象

壓縮和解壓縮對象都是一個可讀可寫流

  • zlib.createGzip:返回Gzip流對象,使用Gzip算法對數據進行壓縮處理
  • zlib.createGunzip:返回Gzip流對象,使用Gzip算法對壓縮的數據進行解壓縮處理
  • zlib.createDeflate:返回Deflate流對象,使用Deflate算法對數據進行壓縮處理
  • zlib.createInflate:返回Deflate流對象,使用Deflate算法對數據進行解壓縮處理

代碼案例:

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與src的區別

href (Hypertext Reference)指定網絡資源的位置,從而在當前元素或者當前文檔和由當前屬性定義的須要的錨點或資源之間定義一個連接或者關係。(目的不是爲了引用資源,而是爲了創建聯繫,讓當前標籤可以連接到目標地址。)

src source(縮寫),指向外部資源的位置,指向的內容將會應用到文檔中當前標籤所在位置。

href與src的區別

一、請求資源類型不一樣:href 指向網絡資源所在位置,創建和當前元素(錨點)或當前文檔(連接)之間的聯繫。在請求 src 資源時會將其指向的資源下載並應用到文檔中,好比 JavaScript 腳本,img 圖片;

二、做用結果不一樣:href 用於在當前文檔和引用資源之間確立聯繫;src 用於替換當前內容;

三、瀏覽器解析方式不一樣:當瀏覽器解析到src ,會**暫停其餘資源的下載和處理,**直到將該資源加載、編譯、執行完畢,圖片和框架等也如此,相似於將所指向資源應用到當前內容。這也是爲何建議把 js 腳本放在底部而不是頭部的緣由。

HTTP Redirect

重定向, 在response Header中增長Location,responseCode能夠是3xx

原理:

在 HTTP 協議中,重定向操做由服務器經過發送特殊的響應(即 redirects)而觸發。HTTP 協議的重定向響應的狀態碼爲 3xx 。瀏覽器在接收到重定向響應的時候,會採用該響應提供的新的 URL ,並當即進行加載;大多數狀況下,除了會有一小部分性能損失以外,重定向操做對於用戶來講是不可見的。

不一樣類型的重定向映射能夠劃分爲三個類別:

  • 永久重定向: 30一、308, 它表示原 URL 不該再被使用,而應該優先選用新的 URL。搜索引擎機器人會在遇到該狀態碼時觸發更新操做,在其索引庫中修改與該資源相關的 URL 。 多用於網站重構。
  • 臨時重定向:30二、30三、307, 有時候請求的資源沒法從其標準地址訪問,可是卻能夠從另外的地方訪問。在這種狀況下能夠使用臨時重定向。搜索引擎不會記錄該新的、臨時的連接。在建立、更新或者刪除資源的時候,臨時重定向也能夠用於顯示臨時性的進度頁面。
  • 特殊重定向:300、304, 304(Not Modified,資源未被修改)會使頁面跳轉到本地陳舊的緩存版本當中(該緩存已過時(?)),而 300(Multiple Choice,多項選擇) 則是一種手工重定向:以 Web 頁面形式呈如今瀏覽器中的消息主體包含了一個可能的重定向連接的列表,用戶能夠從中進行選擇。

優先級:

  1. HTTP 協議的重定向機制永遠最早觸發,即使是在沒有傳送任何頁面——也就沒有頁面被(客戶端)讀取——的狀況下。
  2. HTML 的重定向機制 (``) 會在 HTTP 協議重定向機制未設置的狀況下觸發。
  3. JavaScript 的重定向機制老是做爲最後訴諸的手段,而且只有在客戶端開啓了 JavaScript 的狀況下才起做用。

任何狀況下,只要有可能,就應該採用 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:使用 永久性重定向 要慎重,一旦使用,服務端更改路由設置,用戶若是不清理瀏覽器緩存,就會一直重定向。

HTTP工做流程

通常的通訊流程:首先客戶端發送一個請求(request)給服務器,服務器在接收到這個請求後將生成一個響應(response)返回給客戶端。

一次HTTP操做稱爲一個事務,其工做過程可分爲四步:

1)首先客戶端與服務器須要創建鏈接。只要單擊某個超級連接,HTTP的工做開始。

2)創建鏈接後,客戶端發送一個請求給服務器,請求方式的格式爲:統一資源標識符(URL)、協議版本號,後邊是MIME信息包括請求修飾符、客戶端信息和可能的內容。

3)服務器接到請求後,給予相應的響應信息,其格式爲一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,後邊是MIME信息包括服務器信息、實體信息和可能的內容。

4)客戶端接收服務器所返回的信息經過瀏覽器顯示在用戶的顯示屏上,而後客戶端與服務器斷開鏈接。

若是在以上過程當中的某一步出現錯誤,那麼產生錯誤的信息將返回到客戶端,有顯示屏輸出。對於用戶來講,這些過程是由HTTP本身完成的,用戶只要用鼠標點擊,等待信息顯示就能夠了。

HTTPS

HTTPS(全稱:Hypertext Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL/TLS層。其所用的端口號是443。

HTTPS = HTTP+TLS/SSL
複製代碼

https通訊的優勢:

  • 1)客戶端產生的密鑰只有客戶端和服務器端能獲得;
  • 2)加密的數據只有客戶端和服務器端才能獲得明文;
  • 3)客戶端到服務端的通訊是安全的。

HTTPS和HTTP的區別主要以下:

  1. HTTPS協議須要到CA(證書頒發機構)申請證書,通常免費證書不多,須要交費。
  2. HTTP協議運行在TCP之上,全部傳輸的內容都是明文,HTTPS運行在SSL/TLS之上,SSL/TLS運行在TCP之上,全部傳輸的內容都通過加密的。
  3. HTTP和HTTPS使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
  4. http的鏈接很簡單,是無狀態的;HTTPS協議是由HTTP+SSL協議構建的可進行加密傳輸、身份認證的網絡協議,能夠有效的防止運營商劫持,解決了防劫持的一個大問題,比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應用被准許訪問來自不一樣源服務器上的指定的資源。

可查看: juejin.im/post/5c9c38…

HTTP CSP(內容安全策略)

內容安全策略 (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/…

web攻擊

防護這些劫持最好的方法仍是從後端入手,前端能作的實在太少。並且因爲源碼的暴露,攻擊者很容易繞過咱們的防護手段。可是這不表明咱們去了解這塊的相關知識是沒意義的,本文的許多方法,用在其餘方面也是大有做用。

HTTP爲何不安全?有什麼缺點?

通訊使用明文(不加密),內容可能會被竊聽

不驗證通訊方身份,所以有可能遭遇假裝

沒法證實報文的完整性,因此有可能已遭篡改

一、可能被竊聽

  • HTTP 自己不具有加密的功能,因此也沒法作到通訊總體(使用HTTP協議通訊的請求和響應的內容)進行加密。HTTP 報文使用明文方式發送。
  • 因爲互聯網是由聯通世界各個地方的網絡設施組成,全部發送和接收通過某些設備的數據均可能被截獲或窺視。(例如你們都熟悉的抓包工具:Wireshark),即便通過加密處理,也會被窺視是通訊內容,只是可能很難或者沒法破解出報文的信息而已

二、 認證問題

  • 沒法確認你發送到的服務器就是真正的目標服務器(可能服務器是假裝的)
  • 沒法肯定返回的客戶端是不是按照真實意圖接收的客戶端(多是假裝的客戶端)
  • 沒法肯定正在通訊的對方是否具有訪問權限,Web 服務器上某些重要的信息,只想發給特定用戶即便是無心義的請求也會照單全收。沒法阻止海量請求下的 DoS 攻擊(Denial of Service,拒絕服務攻擊)。

三、 可能被篡改

請求或響應在傳輸途中,遭攻擊者攔截並篡改內容的攻擊被稱爲中間人攻擊(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 攻擊

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 攻擊能夠遵循如下幾種規則:

  1. Get 請求不用於對數據進行修改
  2. Cookie設置HTTP Only
  3. 接口設置禁止跨域
  4. 請求時附帶驗證信息,好比驗證碼或者 Token

CSRF 攻擊的防範

一、驗證碼, 驗證碼被認爲是對抗 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攻擊

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 攻擊的防範

如今主流的瀏覽器內置了防範 XSS 的措施,例如 CSP。但對於開發者來講,也應該尋找可靠的解決方案來防止 XSS 攻擊。

一、HttpOnly 防止劫取 Cookie:

response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly")
複製代碼

二、輸入檢查,由於用戶可能輸入的內容就是注入的腳本,當保存到服務器後,在返顯示到頁面就會被執行以前用戶輸入的注入內容;

解決方案: 對於用戶的任何輸入要進行檢查、過濾和轉義。創建可信任的字符和 HTML 標籤白名單,對於不在白名單之列的字符或者標籤進行過濾或編碼。

在 XSS 防護中,輸入檢查通常是檢查用戶輸入的數據中是否包含 <> 等特殊字符,若是存在,則對特殊字符進行過濾或編碼,這種方式也稱爲 XSS Filter。

// 在 vuejs 中,若是輸入帶 script 標籤的內容,會直接過濾掉
const decodingMap = {
  '&lt;': '<',
  '&gt;': '>',
  '&quot;': '"',
  '&amp;': '&',
  '&#10;': '\n'
}
複製代碼

三、輸出檢查, 服務端的輸出也會存在問題。通常來講,除富文本的輸出外,在變量輸出到 HTML 頁面時,能夠使用編碼或轉義的方式來防護 XSS 攻擊。例如利用 sanitize-html 對輸出內容進行有規則的過濾以後再輸出到頁面中。

防止文件注入型攻擊

防範:

一、文件上傳目錄設置成不可執行

二、判斷文件類型。結合MIME type與文件擴展名,設置文件類型白名單。對於圖片文件,能夠利用圖片庫函數深層次檢查是否真是圖片。

三、重命名文件名。

四、文件服務器使用獨立的域名。

SQL注入

防範:數據與代碼分離,即不用字符串拼湊SQL語句,使用SQL預處理方法(參數使用佔位符 ?)。

XST處理

XST(跨站追蹤)攻擊,防範:關閉Web 服務器的TRACE方法。

問題回答總結

簡述TCP三次握手

  • 第一次握手: 創建鏈接。客戶端發送鏈接請求,發送SYN報文,將seq設置爲X(某個值)。而後,客戶端進入SYN_SEND狀態,等待服務器的確認。
  • 第二次握手: 服務器收到客戶端的SYN報文段。須要對這個SYN報文段進行確認,發送ACK報文,將ack設置爲X+1。同時,本身還要發送SYN請求信息,將seq爲Y。服務器端將上述全部信息一併發送給客戶端,此時服務器進入SYN_RECV狀態。
  • 第三次握手: 客戶端收到服務器的ACK和SYN報文後,進行確認,而後將ack設置爲Y+1,seq設置爲X+1,向服務器發送ACK報文段,這個報文段發送完畢之後,客戶端和服務器端都進入ESTABLISHED狀態,完成TCP三次握手。

第三次握手的緣由是爲了防止已失效的鏈接請求報文段忽然又傳回給服務器進程從而產生錯誤。假設客戶端發送第一次鏈接請求因爲網絡滯留了,因而客戶端又發送了一次請求併成功創建鏈接,數據傳輸完畢後就釋放了鏈接。在釋放鏈接後的某個時間段內客戶端的第一次報文段又到達了服務器並被服務器進程確認,若是沒有第三次握手,則服務器會一直等待客戶端發送數據,從而浪費許多資源。

從輸入URL到頁面加載完成,發生了什麼?

可參考: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){
   &emsp;$("#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協議相對於UDP協議的特色是:TCP協議提供面向鏈接、字節流和可靠的傳輸。

HTTP響應碼你都知道哪些?都是什麼意思?

常見狀態碼

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協議的工做流程?

  • 一、地址解析

  • 二、封裝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 的信道複用能提升性能呢?

  • 同個域名只須要佔用一個 TCP 鏈接,使用一個鏈接並行發送多個請求和響應,這樣整個頁面資源的下載過程只須要一次慢啓動,同時也避免了多個TCP鏈接競爭帶寬所帶來的問題。
  • 並行交錯地發送多個請求/響應,請求/響應之間互不影響。
  • 在HTTP/2中,每一個請求均可以帶一個31bit的優先值,0表示最高優先級, 數值越大優先級越低。有了這個優先值,客戶端和服務器就能夠在處理不一樣的流時採起不一樣的策略,以最優的方式發送流、消息和幀。

針對HTTP/1.1的優化有哪些HTTP/2不在適用?

  • JS文件的合併。咱們如今優化的一個主要方向就是儘可能的減小HTTP的請求數, 對咱們工程中的代碼,研發時分模塊開發,上線時咱們會把全部的代碼進行壓縮合並,合併成一個文件,這樣無論多少模塊,都請求一個文件,減小了HTTP的請求數。可是這樣作有一個很是嚴重的問題:文件的緩存。當咱們有100個模塊時,有一個模塊改了東西,按照以前的方式,整個文件瀏覽器都須要從新下載,不能被緩存。如今咱們有了HTTP/2了,模塊就能夠單獨的壓縮上線,而不影響其餘沒有修改的模塊。
  • 多域名提升瀏覽器的下載速度。以前咱們有一個優化就是把css文件和js文件放到2個域名下面,這樣瀏覽器就能夠對這兩個類型的文件進行同時下載,避免了瀏覽器6個通道的限制,這樣作的缺點也是明顯的,1.DNS的解析時間會變長。2.增長了服務器的壓力。有了HTTP/2以後,根據上面講的原理,咱們就不用這麼搞了,成本會更低。

HTTP1.0 和 1.1 現存的一些問題

  1. HTTP1.x 在傳輸數據時,每次都須要從新創建鏈接,無疑增長了大量的延遲時間,特別是在移動端更爲突出。
  2. HTTP1.x 在傳輸數據時,全部傳輸的內容都是明文,客戶端和服務器端都沒法驗證對方的身份,這在必定程度上沒法保證數據的安全性。
  3. HTTP1.x 在使用時,header 裏攜帶的內容過大,在必定程度上增長了傳輸的成本,而且每次請求 header 基本不怎麼變化,尤爲在移動端增長用戶流量。
  4. 雖然 HTTP1.x 支持了 keep-alive,來彌補屢次建立鏈接產生的延遲,可是 keep-alive 使用多了一樣會給服務端帶來大量的性能壓力,而且對於單個文件被不斷請求的服務 (例如圖片存放網站),keep-alive 可能會極大的影響性能,由於它在文件被請求以後還保持了沒必要要的鏈接很長時間。

HTTPS和HTTP的區別

  1. HTTPS協議須要到CA(證書頒發機構)申請證書,通常免費證書不多,須要交費。
  2. HTTP協議運行在TCP之上,全部傳輸的內容都是明文,HTTPS運行在SSL/TLS之上,SSL/TLS運行在TCP之上,全部傳輸的內容都通過加密的。
  3. HTTP和HTTPS使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
  4. http的鏈接很簡單,是無狀態的;HTTPS協議是由HTTP+SSL協議構建的可進行加密傳輸、身份認證的網絡協議,能夠有效的防止運營商劫持,解決了防劫持的一個大問題,比http協議安全。

如何將HTTP變爲HTTPS?

若是一個網站要全站由 HTTP 替換成 HTTPS,可能須要關注如下幾點:

  1. 安裝 CA 證書,通常的證書都是須要收費的,
  2. 在購買證書以後,在證書提供的網站上配置本身的域名,將證書下載下來以後,配置本身的 web 服務器,同時進行代碼改造。
  3. HTTPS 下降用戶訪問速度。SSL 握手,HTTPS 對速度會有必定程度的下降,可是隻要通過合理優化和部署,HTTPS 對速度的影響徹底能夠接受。在不少場景下,HTTPS 速度徹底不遜於 HTTP,若是使用 SPDY,HTTPS 的速度甚至還要比 HTTP 快。
  4. 相對於 HTTPS 下降訪問速度,其實更須要關心的是服務器端的 CPU 壓力,HTTPS 中大量的密鑰算法計算,會消耗大量的 CPU 資源,只有足夠的優化,HTTPS 的機器成本纔不會明顯增長。

什麼是緩存?

緩存HTTP的倉庫,使經常使用頁面的副本能夠保存在離客戶端更近的地方。

HTTP的緩存機制

HTTP的緩存分爲強緩存和協商緩存(對比緩存)。

HTTP緩存有多種規則,根據是否須要從新向服務器發起請求來分類,可將其分爲強制緩存,對比緩存。

  • 強制緩存若是生效,不須要再和服務器發生交互,而對比緩存無論是否生效,都須要與服務端發生交互
  • 兩類緩存規則能夠同時存在,強制緩存優先級高於對比緩存,也就是說,當執行強制緩存的規則時,若是緩存生效,直接使用緩存,再也不執行對比緩存規則

如何高效利用緩存,上線前端代碼?

一、緩存時間過長,發佈上線了,用戶端還用緩存,會有bug

二、緩存時間太短,重複加載文件過多,浪費帶寬

通常個人處理方式是:

step1:咱們不讓 html 文件緩存( 靜態資源(css、js 、image、audio等) ),每次訪問 html 都去請求服務器。因此瀏覽器每次都能拿到最新的html資源。

step2:將 靜態資源(css、js 、image、audio等)原來的文件名加上每次打包的版本號,或者時間戳、指紋,這樣的好處是,能夠知道靜態資源時哪次打包的,哪些資源時此次更改的,若是出現錯誤,須要回溯版本,也能夠快速回溯。其實這樣仍是不是最優的方法;

對於大公司的靜態資源優化方案是: 用文件的摘要信息來對資源文件進行重命名,把摘要信息放到資源文件發佈路徑中,這樣,內容有修改的資源就變成了一個新的文件發佈到線上,不會覆蓋已有的資源文件。上線過程當中,先全量部署靜態資源,再灰度部署頁面,整個問題就比較完美的解決了。

因此,大公司的靜態資源優化方案,基本上要實現這麼幾個東西:

配置超長時間的本地緩存 —— 節省帶寬,提升性能 採用內容摘要做爲緩存更新依據 —— 精確的緩存控制 靜態資源CDN部署 —— 優化網絡請求 更資源發佈路徑實現非覆蓋式發佈 —— 平滑升級

step3:先上線靜態資源,在上線html

咱們能夠利用webpack工程化工具解決。

HTTP 如何處理大文件的傳輸?

HTTP針對大文件的傳輸場景,能夠使用範圍請求來解決,客戶端將資源一部分一部分傳輸。

通常是:壓縮、分塊、範圍請求、多端數據的流程。

那範圍請求是怎麼處理的呢?

響應頭使用:Accept-Ranges 用來告知客戶端這邊是支持範圍請求的;

請求頭使用: Rang來制定請求哪一部分。Range: bytes=x-y

bytes=x-y 表示範圍格式有:

  • 0-y表示從開始到第 y 個字節。
  • y- 表示從第 y 字節到文件終點。
  • -y表示文件的最後y個字節。
  • x-y 表示文件第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,它表明了信息量是這樣的:

  • 請求必定是多段數據請求
  • 響應體中的分隔符是 00000010101

所以,在響應體中各段數據之間會由這裏指定的分隔符分開,並且在最後的分隔末尾添上--表示結束。

什麼是代理?

代理是位於客戶端和服務器之間的HTTP中間實體。接收全部客戶端的HTTP請求,並將這些請求轉發給服務器(可能會對請求進行修改以後轉發)。

什麼是Agent代理?

用戶Agent代理是表明用戶發起HTTP的客戶端程序。好比Web瀏覽器。另外有些自動發送HTTP請求並獲取內容的代理,好比「網絡蜘蛛」或者「Web機器人」。

如何理解 HTTP 代理?

在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權威指南》

taligarsiel.com/Projects/ho…

cloud.tencent.com/document/pr…

httpwg.org/specs/rfc75…

www.runoob.com/http/http-c…

ye11ow.gitbooks.io/http2-expla…

github.com/creeperyang…

www.cnblogs.com/coco1s/p/57…

developer.mozilla.org/zh-CN/docs/…

developer.mozilla.org/zh-CN/docs/…

相關文章
相關標籤/搜索