肝完《瀏覽器工作原理與實踐》,我總結了這些
作者:wuwhs
簡介:深圳市某科技公司 前端工程師
來源:SegmentFault 思否社區
前言
作爲一名前端 er,日常工作打交道最多(之一)的莫過於熟悉而又陌生的瀏覽器了,熟悉是每天都會基於瀏覽器的應用層面之上碼業務,陌生是很多人可能跟我一樣不熟悉其內部運行原理。
js 是怎樣運行的呢?
精美樣式頁面是怎樣渲染到電腦屏幕的呢?
在開放的互聯網它又是怎樣保證我們個人信息安全的呢?
帶着種種疑雲開始肝李兵老師的《瀏覽器基本原理與實踐》,不得不說,大家之作,通俗易懂,層層撥開雲霧見青天,下面就(非常非常)簡單總結一下。
Chrome 架構:僅僅打開了 1 個頁面,爲什麼有 4 個進程
線程和進程區別:多線程可以並行處理任務,線程不能單獨存在,它是由進程來啓動和管理的。一個進程是一個程序的運行實例。
線程和進程的關係:
1、進程中任意一線程執行出錯,都會導致整個進程的崩潰。
2、線程之間共享進程中的數據。
3、當一個進程關閉後,操作系統會回收進程所佔用的內存。
4、進程之間的內容相互隔離。
單進程瀏覽器:
1、不穩定。單進程中的插件、渲染線程崩潰導致整個瀏覽器崩潰。
2、不流暢。腳本(死循環)或插件會使瀏覽器卡頓。
3、不安全。插件和腳本可以獲取到操作系統任意資源。
多進程瀏覽器:
1、解決不穩定。進程相互隔離,一個頁面或者插件崩潰時,影響僅僅時當前插件或者頁面,不會影響到其他頁面。
2、解決不流暢。腳本阻塞當前頁面渲染進程,不會影響到其他頁面。
3、解決不安全。採用多進程架構使用沙箱。沙箱看成時操作系統給進程上來一把鎖,沙箱的程序可以運行,但是不能在硬盤上寫入任何數據,也不能在敏感位置讀取任何數據。
多進程架構:分爲 瀏覽器進程、渲染進程、GPU 進程、網絡進程、插件進程。
缺點:
1、資源佔用高。
2、體系架構複雜。
面向服務架構:把原來的各種模塊重構成獨立的服務,每個服務都可以在獨立的進程中運行,訪問服務必須使用定義好的接口,通過 IPC 通訊,使得系統更內聚、松耦合、易維護和拓展。
TCP 協議:如何保證頁面文件能被完整送達瀏覽器
-
IP 頭是 IP 數據包開頭的信息,包含 IP 版本、源 IP 地址、目標 IP 地址、生存時間等信息;
-
UDP 頭中除了目的端口,還有源端口號等信息;
-
IP 負責把數據包送達目的主機;
-
UDP 負責把數據包送達具體應用;
-
對於錯誤的數據包,UDP 不提供重發機制,只是丟棄當前的包,不能保證數據的可靠性,但是傳輸速度非常塊;
-
TCP 頭除了包含了目標端口和本機端口號外,還提供了用於排序的序列號,保證了數據完整地傳輸,它的連接可分爲三個階段:建立連接、傳輸數據和斷開連接;
HTTP 請求流程:爲什麼很多站點第二次打開速度會很快
-
瀏覽器中的 HTTP 請求從發起到結束一共經歷如下八個階段:構建請求、查找緩存、準備 IP 和端口、等待 TCP 隊列、建立 TCP 連接、發起 HTTP 請求、服務器處理請求、服務器返回請求和斷開連接;
-
構建請求。瀏覽器構建請求行,構建好後,準備發起網絡請求;
-
查找緩存。在真正發起請求前瀏覽器會查詢緩存中是否有請求資源副本,有則攔截請求,返回資源副本,否則進入網絡請求;
-
準備 IP 地址和端口。HTTP 網絡請求需要和服務器建立 TCP 連接,而建立 TCP 連接需要準備 IP 地址和端口號,瀏覽器需要請求 DNS 返回域名對應的 IP,同時會緩存域名解析結果,供下次查詢使用;
-
等待 TCP 隊列。Chrome 機制,同一個域名同時最多隻能建立 6 個 TCP 連接;
-
建立 TCP 連接。TCP 通過 “三次握手” 建立連接,傳輸數據,“四次揮手”斷開連接;
-
發送 HTTP 請求。建立 TCP 連接後,瀏覽器就可以和服務器進行 HTTP 數據傳輸了,首先會向服務器發送請求行,然後以請求頭形式發送一些其他信息,如果是 POST 請求還會發送請求體;
-
服務器處理請求。首先服務器會返回響應行,隨後,服務器向瀏覽器發送響應頭和響應體。通常服務器返回數據,就要關閉 TCP 連接,如果請求頭或者響應頭有 Connection:keep-alive TCP 保持打開狀態;
導航流程:從輸入 URL 到頁面展示這中間發生了什麼
-
用戶輸入 URL 並回車;
-
瀏覽器進程檢查 URL,組裝協議,構成完整 URL;
-
瀏覽器進程通過進程通信(IPC)把 URL 請求發送給網絡進程;
-
網絡進程接收到 URL 請求後檢查本地緩存是否緩存了該請求資源,如果有則將該資源返回給瀏覽器進程;
-
如果沒有,網絡進程向 web 服務器發起 http 請求(網絡請求),請求流程如下:
-
進行 DNS 解析,獲取服務器 IP 地址,端口
-
利用 IP 地址和服務器建立 tcp 連接構建請求頭信息
-
發送請求頭信息
-
服務器響應後,網絡進程接收響應頭和響應信息,並解析響應內容
-
網絡進程解析響應流程:
-
檢查狀態碼,如果是 301/302,則需要重定向,從 Location 自動讀取地址,重新進行第 4 步,如果是 200,則繼續處理請求
-
200 響應處理:檢查響應類型 Content-Type,如果是字節流類型,則將該請求提交給下載管理器,該導航流程結束,不再進行後續渲染。如果是 html 則通知瀏覽器進程準備渲染進程進行渲染
-
準備渲染進程:
-
瀏覽器進程檢查當前 URL 是否和之前打開的渲染進程根域名是否相同,如果相同,則複用原來的進程,如果不同,則開啓新的渲染進程
-
傳輸數據、更新狀態:
-
渲染進程準備好後,瀏覽器向渲染進程發起 “提交文檔” 的消息,渲染進程接收到消息和網絡進程建立傳輸數據的“管道”
-
渲染進程接收完數據後,向瀏覽器發送 “確認提交”
-
瀏覽器進程接收到確認消息後 engine 瀏覽器界面狀態:安全、地址 URL、前進後退的歷史狀態、更新 web 頁面
渲染流程(上):HTML、CSS 和 JavaScript 是如何變成頁面的
-
瀏覽器不能直接理解 HTML 數據,需要將其轉化爲 DOM 樹結構;
-
生成 DOM 樹後,根據 CSS 樣式表,計算出 DOM 樹所有節點樣式;
-
創建佈局樹:遍歷 DOM 樹所有可見節點,把這些節點加到佈局中,不可見節點忽略,如 head 標籤下所有內容,display: none 元素;
渲染流程(下):HTML、CSS 和 JavaScript 是如何變成頁面的
-
分層:層疊上下文屬性的元素(比如定位屬性元素、透明屬性元素、CSS 濾鏡屬性元素)提升爲單獨的一層,需要裁剪的地方(比如出現滾動條)也會被創建爲圖層;
-
圖層繪製:完成圖層樹構建後,渲染引擎會對圖層樹每一層進行繪製,把一個圖層拆分成小的繪製指令,再把指令按照順序組成一個帶繪製列表;
-
有些情況圖層很大,一次繪製所有圖層內容,開銷太大,合成線程會將圖層劃分爲圖塊(256x256 或者 512x512);
-
合成線程將圖塊提交給柵格線程進行柵格化,將圖塊轉換爲位圖。柵格化過程都會使用 GPU 加速,生成的位圖保存週期 GPU 內存中;
-
一旦所有圖塊都被柵格化,合成線程會生成一個繪製圖塊命令(DrawQuad),然會將命令提交給瀏覽器進程,viz 組件接收到該指令,將頁面內容繪製到內存中,顯示在屏幕上;
-
重排:通過 JavaScript 或者 CSS 修改元素幾何位置屬性,會觸發重新佈局,解析後面一系列子階段;重繪:不引起佈局變換,直接進入繪製及其以後子階段;合成:跳過佈局和繪製階段,執行的後續操作,發生在合成線程,非主線程;
變量提升:javascript 代碼是按順序執行的嗎
-
JavaScript 代碼在執行之前需要先編譯,在編譯階段,變量和函數會被存放到變量環境中,變量默認值會被設置爲 undefined;
-
在代碼執行階段,JavaScript 引擎會從變量環境中查找自定義的變量和函數;
-
如果在編譯階段,竄愛兩個相同的函數,那麼最終放在變量環境中的是最後定義的那個,後定義的覆蓋先定義的;
調用棧:爲什麼 JavaScript 代碼會出現棧溢出
-
每調用一個函數,JavaScript 引擎會爲其創建執行上下文壓入調用棧,然後,JavaScript 引擎開始執行函數代碼;
-
如果一個函數 A 調用另外一個函數 B,那麼 JavaScript 引擎會爲 B 函數創建執行上下文,並將 B 函數的執行上下文壓入棧頂;
-
當前函數執行完畢後,JavaScript 引擎會將該函數的執行上下文彈出棧;
-
當分配的調用棧空間被佔滿時,會引發 “堆棧溢出” 問題;
塊級作用域:var 缺陷以及爲什麼要引入 let 和 const
-
let、const 申明的變量不會被提升。在 javascript 引擎編譯後,會保存在詞法環境中;
-
塊級作用域在代碼執行時,將 let、const 變量存放在詞法環境的一個單獨的區域。詞法環境內部維護一個小型的棧結構,作用域內部變量壓入棧頂。作用域執行完,從棧頂彈出;
作用域鏈和閉包:代碼中出現相同的變量,JavaScript 引擎如何選擇
-
使用一個變量,JavaScript 引擎會在當前的執行上下文中查找變量,如果沒有找到,會繼續在 outer(執行環境指向外部執行上下文的引用)所指向的執行上下文中查找;
-
JavaScript 執行過程,作用域鏈是由詞法作用域決定,而詞法作用域是由代碼中函數聲明的位置決定;
-
根據詞法作用域的規則,內部函數總是可以訪問其外部函數中聲明的變量,當通過調用一個外部函數返回一個內部函數後,即使外部函數已經執行結束了,但是內部函數引用外部函數的變量依舊保存在內存中,把這些變量的集合稱爲閉包;
this:從 JavaScript 執行上下文視角講 this
當執行 new CreateObj 的時候,JavaScript 引擎做了四件事:
-
首先創建一個控對象 tempObj;
-
接着調用 CreateObj.call 方法,並將 tempObj 作爲 call 方法的參數,這樣當 createObj 的執行上下文創建時,它的 this 就指向 tempObj 對象;
-
然後執行 CreateObj 函數,此時的 CreateObj 函數執行上下文中的 this 指向 tempObj 對象;
-
最後返回 tempObj 對象。
this 的使用分爲:
-
當函數最爲對象的方法調用時,函數中的 this 就是該對象;
-
當函數被正常調用時,在嚴格模式下,this 值是 undefined,非嚴格模式下 this 指向的是全局對象 window;
-
嵌套函數中的 this 不會繼承外層函數的 this 值;
-
箭頭函數沒有自己的執行上下文,this 是外層函數的 this。
棧空間和堆空間:數據是如何存儲的
動態語言:在使用時需要檢查數據類型的語言。
弱類型語言:支持隱式轉換的語言。
JavaScript 中的 8 種數據類型,它們可以分爲兩大類——原始類型和引用類型。
原始類型數據存放在棧中,引用類型數據存放在堆中。堆中的數據是通過引用與變量關係聯繫起來的。
從內存視角瞭解閉包:詞法掃描內部函數,引用了外部函數變量,堆空間創建一個 “closure” 對象,保存變量。
垃圾回收:垃圾數據如何自動回收
-
棧中數據回收:執行狀態指針 ESP 在執行棧中移動,移過某執行上下文,就會被銷燬;
-
堆中數據回收:V8 引擎採用標記 - 清除算法;
-
V8 把堆分爲兩個區域——新生代和老生代,分別使用副、主垃圾回收器;
-
副垃圾回收器負責新生代垃圾回收,小對象(1 ~ 8M)會被分配到該區域處理;
-
新生代採用 scavenge 算法處理:將新生代空間分爲兩半,一半空閒,一半存對象,對對象區域做標記,存活對象複製排列到空閒區域,沒有內存碎片,完成後,清理對象區域,角色反轉;
-
新生代區域兩次垃圾回收還存活的對象晉升至老生代區域;
-
主垃圾回收器負責老生區垃圾回收,大對象,存活時間長;
-
新生代區域採用標記 - 清除算法回收垃圾:從根元素開始,遞歸,可到達的元素活動元素,否則是垃圾數據;
-
爲了不造成卡頓,標記過程被切分爲一個個子標記,交替進行。
編譯器和解析器:V8 如何執行一段 JavaScript 代碼的
-
計算機語言可以分爲兩種:編譯型和解釋型語言。編譯型語言經過編譯器編譯後保留機器能讀懂的二進制文件,比如 C/C++,go 語言。解釋型語言是在程序運行時通過解釋器對程序進行動態解釋和執行,比如 Python,JavaScript 語言。
-
編譯型語言的編譯過程:編譯器首先將代碼進行詞法分析、語法分析,生成抽象語法樹(AST),然後優化代碼,最後生成處理器能夠理解的機器碼;
-
解釋型語言解釋過程:解釋器會對代碼進行詞法分析、語法分析,並生產抽象語法樹(AST),不過它會再基於抽象語法樹生成字節碼,最後根據字節碼執行程序;
-
AST 的生成:第一階段是分詞(詞法分析),將一行行源碼拆解成一個個 token(語法上不可再分、最小單個字符)。第二階段是解析(語法分析),將上一步生成的 token 數據,根據語法規則轉爲 AST,這一階段會檢查語法錯誤;
-
字節碼存在的意義:直接將 AST 轉化爲機器碼,執行效率是非常高,但是消耗大量內存,從而先轉化爲字節碼解決內存問題;
-
解釋器 ignition 在解釋執行字節碼,同時會手機代碼信息,發現某一部分代碼是熱點代碼(HotSpot),編譯器把熱點的字節碼轉化爲機器碼,並保存起來,下次使用;
-
字節碼配合解釋器和編譯器的計數實現稱爲即時編譯(JIT)。
消息隊列和事件循環:頁面是怎麼活起來的
-
每個渲染進程都有一個主線程,主線程會處理 DOM,計算樣式,處理佈局,JavaScript 任務以及各種輸入事件;
-
維護一個消息隊列,新任務(比如 IO 線程)添加到消息隊列尾部,主線程循環地從消息隊列頭部讀取任務,執行任務;
-
解決處理優先級高的任務:消息隊列的中的任務稱爲宏任務,每個宏任務中都會包含一個微任務隊列,在執行宏任務的過程中,如果 DOM 有變化,將該變化添加到微任務隊列中;
-
解決單個任務執行時長過久:JavaScript 通過回調功能來規避。
webapi:setTimeout 是怎麼實現的
-
JavaScript 調用 setTimeout 設置回調函數的時候,渲染進程會創建一個回調任務,延時執行隊列存放定時器任務;
-
當定時器任務到期,就會從延時隊列中取出並執行;
-
如果當前任務執行時間過久,會影響延時到期定時器任務的執行;
-
如果 setTimeout 存在嵌套調用(5 次以上),判斷該函數方法被阻塞,那麼系統會設置最短時間間隔爲 4 秒;
-
未激活的頁面,setTimeout 執行最小間隔是 1000 毫秒,目的是爲了降低加載損耗;
-
延時執行時間最大值是 24.8 天,因爲延時值是以 32 個 bit 存儲的;
-
setTimeout 設置的回調函數中的 this 指向全局 window。
webpai:XMLHttpRequest 是怎麼實現的
-
XMLHttpRequest onreadystatechange 處理流程:未初始化 -> OPENED -> HEADERS_RECEIVED -> LOADING -> DONE;
-
渲染進程會將請求發送給網絡進程,然後網絡進程負責資源下載,等網絡進程接收到數據後,利用 IPC 通知渲染進程;
-
渲染進程接收到消息之後,會將 xhr 回調函數封裝成任務並添加到消息隊列中,等主線程循環系統執行到該任務的時候,會根據相關狀態來調用回調函數。
宏任務和微任務:不是所有的任務都是一個待遇
-
消息隊列中的任務爲宏任務。渲染進程內部會維護多個消息隊列,比如延時執行隊列和普通消息隊列,主線程採用 for 循環,不斷地從這些任務隊列中取出任務並執行;
-
微任務是一個需要異步執行的函數,執行時機是在主函數執行結束之後、當前宏任務結束之前;
-
V8 在執行 javascript 腳本時,會爲其創建一個全局執行上下文,同時會創建一個微任務隊列;
-
執行微任務過程中產生的微任務不會推遲到下個宏任務中執行,而是在當前宏任務中繼續執行;
使用 Promise 告別回調函數
-
使用 Promise 解決了回調地獄問題,消滅嵌套和多次處理;
-
模擬實現 Promise
function Bromise(executor) {
var _onResolve = null
this.then = function (onResolve) {
_onResolve = onResolve
}
function resolve(value) {
setTimeout(() => {
_onResolve(value)
}, 0)
}
executor(resolve, null)
}
async await 使用同步方式寫異步代碼
-
生成器函數是一個帶星號函數,而且是可以暫停執行和回覆執行的;
-
生成器函數內部執行一段代碼,遇到 yield 關鍵字,javascript 引擎返回關鍵字後面的內容給外部,並且暫停該函數的執行;
-
外部函數可以同步 next 方法恢復函數的執行;
-
協程是一種比線程更加輕量級的存在,協程可以看成是跑在線程上的任務,一個線程可以存在多個協程,但是同時只能執行一個協程,如果 A 協程啓動 B 協程,A 爲 B 的父協程;
-
協程不被操作協同內核所管理,而完全由程序所控制,這樣性能提升;
-
await xxx 會創建一個 Promise 對象,將 xxx 任務提交給微任務隊列;
-
暫停當前協程的執行,將主線程的控制權力轉交給父協程執行,同時將 Promise 對象返回給父協程,繼續執行父協程;
-
父協程執行結束之前會檢查微任務隊列,微任務隊列中有 resolve(xxx) 等待執行,觸發 then 的回調函數;
-
回調函數被激活後,會將主線程的控制權交給協程,繼續執行後續語句,完成後將控制權還給父協程。
頁面性能分析:利用 chrome 做 web 性能分析
- Chrome 開發者工具(簡稱 DevTools)是一組網頁製作和調試的工具,內嵌於 Google Chrome 瀏覽器中。它一共包含了 10 個功能面板,包括了 Elements、Console、Sources、NetWork、Performance、Memory、Application、Security、Audits 和 Layers。
DOM 樹:JavaScript 是如何影響 DOM 樹構建的
-
HTML 解析器(HTMLParse)負責將 HTML 字節流轉換爲 DOM 結構;
-
HTML 解析器並不是等整個文檔加載完成之後再解析,而是網絡進程加載流多少數據,便解析多少數據;
-
字節流轉換成 DOM 三個階段:1、字節流轉換爲 Token;2、維護一個 Token 棧,遇到 StartTag Token 入棧,遇到 EndTag Token 出棧;3、爲每個 Token 創建一個 DOM 節點;
-
JavaScript 文件和 CSS 樣式表文件都會阻塞 DOM 解析;
渲染流水線:CSS 如何影響首次加載時的白屏時間?
-
DOM 構建結束之後,css 文件還未下載完成,渲染流水線空閒,因爲下一步是合成佈局樹,合成佈局樹需要 CSSOM 和 DOM,這裏需要等待 CSS 加載結束並解析成 CSSOM;
-
CSSOM 兩個作用:提供給 JavaScript 操作樣式表能力,爲佈局樹的合成提供基礎樣式信息;
-
在執行 JavaScript 腳本之前,如果頁面中包含了外部 CSS 文件的引用,或者通過 style 標籤內置了 CSS 內容,那麼渲染引擎還需要將這些內容轉化爲 CSSOM,因爲 JavaScript 有修改 CSSOM 的能力,所以在執行 JavaScript 之前,還需要依賴 CSSOM。也就是說 CSS 在部分情況下也會阻塞 DOM 的生成。
分層和合成機制:爲什麼 CSS 動畫比 JavaScript 高效
-
顯示器固定刷新頻率是 60HZ,即每秒更新 60 張圖片,圖片來自顯卡的前緩衝區;
-
顯卡的職責是合成新的圖像,保存在後緩衝區,然後後緩衝區和前緩衝區互換,顯卡更新頻率和顯示前刷新頻率不一致,就會造成視覺上的卡頓;
-
渲染流水線生成的每一副圖片稱爲一幀,生成一幀的方式有重排、重繪和合成三種;
-
重排會根據 CSSOM 和 DOM 計算佈局樹,重繪沒有重新佈局階段;
-
生成佈局樹之後,渲染引擎根據佈局樹特點轉化爲層樹,每一層解析出繪製列表;
-
柵格線程根據繪製列表中的指令生成圖片,每一層對應一張圖片,合成線程將這些圖片合成一張圖片,發送到後緩存區;
-
合成線程會將每個圖層分割成大小固定的圖塊,優先繪製靠近視口的圖塊;
頁面性能:如何系統優化頁面
-
加載階段:減少關鍵資源個數,降低關鍵資源大小,降低關鍵資源的 RTT 次數;
-
交互階段:減少 JavaScript 腳本執行時間,避免強制同步佈局:操作 DOM 的同時獲取佈局樣式會引發,避免佈局抖動:多次執行強制佈局和抖動,合理利用 CSS 合成動畫:標記 will-change,避免頻繁的垃圾回收;
-
CSS 實現一些變形、漸變、動畫等特效,這是由 CSS 觸發的,並且是在合成線程中執行,這個過程稱爲合成,它不會觸發重排或者重繪;
虛擬 DOM:虛擬 DOM 和真實 DOM 有何不同
-
當有數據更新時, React 會生產一個新的虛擬 DOM,然會拿新的虛擬 DOM 和之前的虛擬 DOM 進行比較,這個過程找出變化的節點,然後將變化的節點應用到 DOM 上;
-
最開始的時候,比較兩個 DOM 的過程是在一個遞歸函數里執行的,其核心算法是 reconciliation。通常情況,這個比較過程執行很快,不過虛擬 DOM 比較複雜時,執行比較函數可能佔據主線程比較久的時間,這樣會導致其他任務的等待,造成頁面卡頓。React 團隊重寫了 reconciliation 算法,稱爲 Fiber reconciler,之前老的算法稱爲 Stack reconciler;
PWA:解決 web 應用哪些問題
-
PWA(Progressive Web App),漸進式 Web 應用。一個漸進式過渡方案,讓普通站點過渡到 Web 應用,降低站點改造代價,逐漸支持新技術,而不是一步到位;
-
PWA 引入 ServiceWorker 來試着解決離線存儲和消息推送問題,引入 mainfest.json 來解決一級入口問題;
-
暗轉了 ServiceWorker 模塊之後,WebApp 請求資源時,會先通過 ServiceWorker,讓它判斷是返回 Serviceworker 緩存的資源還是重新去網絡請求資源,一切的控制權交給 ServiceWorker 來處理;
-
在目前的 Chrome 架構中,Service Worker 是運行在瀏覽器進程中的,因爲瀏覽器進程生命週期是最長的,所以在瀏覽器的生命週期內,能夠爲所有的頁面提供服務;
WebComponent:像搭積木一樣構建 web 應用
-
CSS 的全局屬性會阻礙組件化,DOM 也是阻礙組件化的一個因素,因爲頁面中只有一個 DOM,任何地方都可以直接讀取和修改 DOM;
-
WebComponent 提供了對局部試圖封裝能力,可以讓 DOM、CSSOM 和 JavaScript 運行在局部環境中;
-
template 創建模版,查找模版內容,創建影子 DOM,模版添加到影子 DOM 上;
-
影子 DOM 可以隔離全局 CSS 和 DOM,但是 JavaScript 是不會被隔離的;
HTTP1:HTTP1 性能優化
-
HTTP/0.9 基於 TCP 協議,三次握手建立連接,發送一個 GET 請求行(沒有請求頭和請求體),服務器接收請求之後,讀取對應 HTML 文件,數據以 ASCII 字符流返回,傳輸完成斷開連接;
-
HTTP/1.0 增加請求頭和響應頭來進行協商,在發起請求時通過請求頭告訴服務器它期待返回什麼類型問題、什麼形式壓縮、什麼語言以及文件編碼。引入來狀態嗎,Cache 機制等;
-
HTTP/1.1 改進持久化連接,解決建立 TCP 連接、傳輸數據和斷開連接帶來的大量開銷,支持在一個 TCP 連接上可以傳輸多個 HTTP 請求,目前瀏覽器對於一個域名同時允許建立 6 個 TCP 持久連接;
-
HTTP/1.1 引入 Chunk transfer 支持動態生成內容:服務器將數據分割成若干任意大小的數據塊,每個數據塊發送時附上上個數據塊的長度,最後使用一個零長度的塊作爲發送數據完成的標誌。在 HTTP/1.1 需要在響應頭中設置完整的數據大小,如 Content-Length。
HTTP2:如何提升網絡速度
-
HTTP/1.1 主要問題:TCP 慢啓動;同時開啓多條 TCP 連接,會競爭固定寬帶;對頭阻塞問題;
-
HTTP/2 在一個域名下只使用一個 TCP 長連接和消除對頭阻塞問題;
-
多路複用的實現:HTTP/2 添加了二進制分幀層,將發送或響應數據經過二進制分幀處理,轉化爲一個個帶有請求 ID 編號的幀,服務器或者瀏覽器接收到響應幀後,根據相同 ID 幀合併爲一條完整信息;
-
設置請求優先級:發送請求可以設置請求優先級,服務器可以優先處理;
-
服務器推送:請求一個 HTML 頁面,服務器可以知道引用了哪些 JavaScript 和 CSS 文件,附帶一起發送給瀏覽器;
-
頭部壓縮:對請求頭和響應頭進行壓縮;
HTTP3:甩掉 TCP、TCL 包袱,構建高效網絡
-
雖然 HTTP/2 解決了應用層面的對頭阻塞問題,不過和 HTTP/1.1 一樣,HTTP/2 依然是基於 TCP 協議,而 TCP 最初是爲了單連接而設計;
-
TCP 可以看成是計算機之間的一個虛擬管道,數據從一端發送到另一端會被拆分爲一個個按照順序排列的數據包,如果在傳輸過程中,有一個數據因爲網絡故障或者其他原因丟失,那麼整個連接會處於暫停狀態,只有等到該數據重新傳輸;
-
由於 TCP 協議僵化,也不可能使用新的協議,HTTP/3 選擇了一個折衷的方法,基於現有的 UDP 協議,實現類似 TC 片多路複用,傳輸可靠等功能,稱爲 QULC 協議;
-
QULC 實現類似 TCP 流量控制,傳輸可靠功能;集成 TLS 加密功能;實現多路複用功能;
同源策略:爲什麼 XMLHttpRequst 不能跨域請求
-
協議、域名和端口號相同的 URL 是同源的;
-
同源策略會隔離不同源的 DOM、頁面數據和網絡通信;
-
頁面可以引用第三方資源,不過暴露出諸如 XSS 問題,引入內容安全策略 CSP 限制;
-
默認 XMLHttpRequest 和 Fetch 不能跨站請求資源,引入跨域資源共享(CORS)進行跨域訪問控制;
跨站腳本攻擊 XSS:爲什麼 cookie 中有 httpOnly 屬性
-
XSS 跨站腳本,往 HTML 文件中注入惡意代碼,對用戶實施攻擊;
-
XSS 攻擊主要有存儲型 XSS 攻擊、反射型 XSS 攻擊和 DOM 的 XSS 攻擊;
-
阻止 XSS 攻擊:服務器對腳本進行過濾或轉碼,利用 CSP 策略,使用 HttpOnly;
CSRF 攻擊:陌生連接不要隨便點
-
CSRF 跨站請求僞造,利用用戶的登錄狀態,通過第三方站點攻擊;
-
避免 CSRF 攻擊:利用 SameSite(三種模式:Strict、Lax、None) 讓瀏覽器禁止第三方站點發起請求攜帶關鍵 Cookie;驗證請求的來源站點,請求頭中的 Referer 和 Origin 屬性;利用 CSRF Token;
沙盒:頁面和系統之間的隔離牆
-
瀏覽器被劃分爲瀏覽器內核和渲染內核兩個核心模塊,其中瀏覽器內核石油網絡進程、瀏覽器主進程和 GPU 進程組成的,渲染內核就是渲染進程;
-
瀏覽器中的安全沙箱是利用操作系統提供的安全技術,讓渲染進程在執行過程中無法訪問或者修改操作系統中的數據,在渲染進程需要訪問系統資源的時候,需要通過瀏覽器內核來實現,然後將訪問的結果通過 IPC 轉發給渲染進程;
-
站點隔離(Site Isolation)將同一站點(包含相同根域名和相同協議的地址)中相互關聯的頁面放到同一個渲染進程中執行;
-
實現站點隔離,就可以將惡意的 iframe 隔離在惡意進程內部,使得它無法繼續訪問其他 iframe 進程的內容,因此無法攻擊其他站點;
HTTPS:讓數據傳輸更安全
-
在 TCP 和 HTTP 之間插入一個安全層,所有經過安全層的數據都會被加密或者解密;
-
對稱加密:瀏覽器發送加密套件列表和一個隨機數 client-random,服務器會從加密套件中選取一個加密套件,然後生成一個隨機數 service-random,返回給瀏覽器。這樣瀏覽器和服務器都有相同 client-random 和 service-random,再用相同的方法將兩者混合生成一個密鑰 master secret,雙方就可以進行數據加密傳輸了;
-
對稱加密缺點:client-random 和 service-random 的過程都是明文,黑客可以拿到協商的加密套件和雙方隨機數,生成密鑰,數據可以被破解;
-
非對稱加密:瀏覽器發送加密套件列表給服務器,服務器選擇一個加密套件,返回加密套件和公鑰,瀏覽器用公鑰加密數據,服務器用私鑰解密;
-
非對稱加密缺點:加密效率太低,不能保證服務器發送給瀏覽器的數據安全,黑客可以獲取公鑰;
-
對稱加密結合非對稱加密:瀏覽器發送對稱加密套件列表、非對稱加密列表和隨機數 client-random 給服務器,服務器生成隨機數 service-random,選擇加密套件和公鑰返回給瀏覽器,瀏覽器利用 client-random 和 service-random 計算出 pre-master,然後利用公鑰給 pre-master 加密,向服務器發送加密後的數據,服務器用私鑰解密出 pre-master 數據,結合 client-random 和 service-random 生成對稱密鑰,使用對稱密鑰傳輸加密數據;
-
引入數字證書是爲了證明 “我就是我”,防止 DNS 被劫持,僞造服務器;
-
證書的作用:一個是向瀏覽器證明服務器的身份,另一個是包含服務器公鑰;
-
數字簽名過程:CA 使用 Hash 函數技術明文信息,得出信息摘要,然後 CA 使用私鑰對信息摘要進行加密,加密後的祕文就是數字簽名;
-
驗證數字簽名:讀取證書明文信息,使用相同 Hash 函數計算得到信息摘要 A,再利用 CA 的公鑰解密得到 B,對比 A 和 B,如果一致,則確認證書合法;
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/jeEkBnsqA6O88Wq3ELdSHw