備註:
因為文章太長,所以將它分為三部分,本文是第三部分。
第一部分:深入淺出經典面試題:從瀏覽器中輸入URL到頁面載入發生了什麼 - Part 1
第二部分:深入淺出經典面試題:從瀏覽器中輸入URL到頁面載入發生了什麼 - Part 2
第三部分:深入淺出經典面試題:從瀏覽器中輸入URL到頁面載入發生了什麼 - Part 3
HTTP/HTTPS請求和響應
前面TCP連線已經建立好了,意味著橋已經搭好了,下一步就該傳輸HTTP訊息了。因為HTTP我們都很熟悉,很常見,也不是那麼底層,理解起來輕鬆不少。
還是抓包來分析,不過這次不用Wireshark來抓,因為不太直觀,這次直接用Chrome自帶的Developer Tools。
HTTP 請求
下圖展示了HTTP請求Header
Request URL:就是請求的URL
Request Method: GET, POST, PUT,DELETE, OPTIONS, HEAD
接下來就是其他報文頭,常見的請求報頭有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。
HTTP 響應
下圖展示了HTTP響應Header
最常見的就是Status Code( 200, 302, 307, 404, 500),server等。
HTTP 10問
HTTP問題簡單,那就直接列舉幾個問題,有些問題我給出詳細答案。
1. HTTP METHOD有哪幾種,分別是什麼?
常見問題,不多解釋。
2. HTTP的PUT/DELETE/等使用時需要注意什麼?
有一點需要特別注意,有的瀏覽器是不支援的,所以在使用和實現時需要仔細評估好自己客戶端的能力。
3. HTTP的OPTIONS用來做什麼?
OPTIONS一般用來獲取目標資源的通訊選項,例如確認允許的HTTP Method.下面的這個例子來在Mozilla官網https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS。
請求:
curl -X OPTIONS http://example.org -i
響應:
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
看紅色的返回部分,意思是說該URL允許的HTTP Method 為OPTIONS、GET、HEAD以及POST。
那麼OPTIONS一般用在哪裡呢?是的,CORS。如果您開發過SPA,或者您的前端的邏輯和互動完全用JavaScript來實現的,肯定會碰到此問題。所謂JavaScript實現,目前比交流行的有VueJS,AngularJS,React等流行框架。如何解決這個問題?最常用的方法是是前端和後端在同一個域名下。如果不在同一個域名下,需要在後端實現支援CORS的功能,目前Spring/Spring Boot已經有類似功能支援CORS,實現起來蠻簡單的,具體可以參看https://spring.io/blog/2015/06/08/cors-support-in-spring-framework,不在贅述。
關於CORS,最難的不是這裡,在我遇到的Case裡,比這個更復雜,如果前端是SPA,而且在某種情況下,訪問任何前端頁面都會進行跳轉,這是需求。但是因為是SPA的架構,會出現OPTIONS(這是瀏覽器關於CORS支援的流程),這會使整個HTTP 流程變得紊亂,也是一個很棘手的問題。
不管怎麼說,CORS屬於安全性這一塊,後面在軟體安全(包括Web)方面專門寫吧。在過去幾年裡,因為公司和客戶在產品安全和資料安全放在了一個很高的位置,而我又是去負責這一塊,所以自己在安全方面積累了大量的實戰經驗,非常寶貴。
4. 上述訪問qq的HTTP response裡的server哪裡不合適,需要注意什麼?
server的值是squid/3.5.24,不合適之處在哪裡?也許部分人是不清楚的。其實很簡單,不應該把squid的版本資訊放在這裡。為什麼?
如果web server軟體是自己公司開發的,私有的,不開源的,這也罷了,沒人知道你的web server是怎麼實現的,但這並不代表web server沒有漏洞,不代表別人發現不了漏洞。
但如果用的是開源的,例如Apache HTTPd,Apache Tomcat,Ngnix等,就需要注意了,每個版本都有安全漏洞,而且這些安全漏洞都有專門的記錄,看看隔三差五報告的CVE,就知道漏洞多少了。所以,如果使用開源軟體,很容易將自己的web server處於一個具有潛在風險的位置,所以不要加上版本號。
騰訊作為全球頂級的大公司,這方面不注意,實在是有點說不過去。如果有騰訊的朋友看到這裡,還是改過來吧。
和上面一樣,這也是屬於安全性問題,有時間我再寫吧。
5. Status Code 302與307的區別是什麼?
都屬於跳轉,但是區別在哪裡呢?
我們看看307在協議裡是怎麼定義的?參看rfc2616第10章節
10.3.8 307 Temporary Redirect
The requested resource resides temporarily under a different URI. Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.
The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the information necessary for a user to repeat the original request on the new URI.
If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.
在 GET、HEAD 這些冪等的請求方式上,302、307 沒區別,但對於 POST 就不同了,大部分瀏覽器 都會 302 會將 POST 請求轉為 GET,而 307則不一樣,規範要求瀏覽器繼續向 Location 的地址 POST 內容。
舉個例子解釋一下,假設正在POST一個訊息,裡面的Body有1M內容,在307的情況下,這1M的內容會繼續發過去,但在302的情況下,則不會。
6. 在HTTP Response裡Connection的用法需要注意什麼?
不解釋過多,keep-alive,closed用法不一樣,根據實際情況而定,在優化網路時經常用到。
需要注意的是,Connection在通訊領域會一些場景下會造成一些麻煩,尤其是在監控某個HTTP Session的flow時。
7. 在HTTP Response裡Strict-Transport-Security(HSTS)怎麼用?
HSTS一般大公司都會用,在我實際的專案涉及到HTTPS,為了實現某個功能,HSTS成了一個跨不過去的坎,遇到過很大問題。大家自己多看看吧。
8. 可以抓HTTPS的包瞭解HTTP請求和響應嗎?有什麼方法?
不多解釋,但提供2個軟體名字,Fiddler,HTTP Analyzer。
9. 為什麼對效能要求高的場景下不使用HTTP作為協議?例如在商用裡,RPC開源專案一般不使用HTTP作為傳輸協議?而在5G下使用HTTP協議呢?
有一點是需要注意的,HTTP的訊息頭太多了,會造成訊息體特別大,影響效能,而且有些場景下這些訊息頭大部分都是無用的。
但是在5G裡,為什麼3GPP組織會採用HTTP協議作為各個reference point的interface的實現呢?大家體會一下。
10. HTTP協議(包括HTTP/2.0)有了解嗎?
不多解釋,但是HTTP/2.0還是需要了解一下,優勢和缺點。
瀏覽器解析和渲染頁面
現在瀏覽器接收到了server的返回內容,接下來瀏覽器該把內容呈現給使用者了。
Server返回的內容有哪些呢?這裡只以HTML頁面為例(API返回的JSON資料或XML資料不在討論範圍內)。
一個頁面一般包含HTML、CSS、 JS、 圖片等檔案,那麼瀏覽器收到這些檔案後該如何渲染(render)他們呢?
以下部分很多參考下面2篇文章:
- https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/
- https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction
瀏覽器的組成
首先我們先了解一下瀏覽器的元件構成,以及每個元件的功能,下圖是瀏覽器包括的幾個部分:
- User Interface: UI元件包括位址列,前進/後退按鈕,書籤選單等。
- Browser Engine: 在UI元件和渲染引擎間採取一些action.
- Rendering engine : 負責顯示請求的內容。例如,如果是HTML頁面,它將解析HTML,CSS,並將解析的內容顯示在螢幕上。
不同的瀏覽器使用不同的渲染引擎:
- IE使用Trident
- Firefox使用Gecko
- Safari使用WebKit
- Chrome和Opera(版本15開始)使用Blink。它是基於Webkit開發的。
4. Networking: 負責網路呼叫,例如HTTP請求。在不同的平臺有不同的實
5. UI backend: 主要用來繪畫基本的UI元素,例如下拉框,Windows等。這個UI後臺暴露一些通用的介面,並不依賴平臺的。
6. JavaScript interpreter. 用來解析和執行JavaScript code。
7. Data storage. 資料持久化的那一層。瀏覽器可能需要儲存各種各樣的資料,例如Cookie。瀏覽器也得支援我們常用的LocalStorage, IndexedDB,WebSQL以及FileSystem。
渲染頁面的主要流程
下面是瀏覽器的渲染引擎的主要步驟。
渲染引擎解析HTML文件,並將HTML包含的元素轉化為一個個DOM,並構建為一個DOM樹。然後引擎開始解析來自CSS檔案或直接嵌在HTML頁面的CSS樣式資料,這些樣式資訊又會構建另外一個樹:渲染樹。
渲染樹包含了多個矩形,這些矩形包含了顏色,大小,位置等屬性,而且會按照對應的順序顯示在螢幕上。
當渲染樹構造完畢後,接下來進入佈局的程式,在這個程式裡,渲染引擎會給每個DOM元素安排精確的座標,並根據座標在螢幕上顯示。
接下來是遍歷渲染樹,UI Backend層會將一個個DOM元素繪畫在螢幕上繪畫出來。
需要注意的是,上面是一個漸進的過程,理解這一點非常重要。但是為了得到更好的使用者體驗,瀏覽器會邊解析邊渲染,它並不會等到所有HTML解析完了才開始構造和佈局渲染樹。當部分內容正在解析渲染時,另外一部分正從網路那邊下載下來呢。
下面2個圖是WebKit和Gecko的渲染引擎的流程,我們發現他們大致相同的。
下面是DOM樹,渲染樹的樹形結構。
渲染引擎是單執行緒工作的,除了網路操作,其他所有的都是單執行緒的。在Firefox和Safari,它們自己就是主執行緒,而Chrome就是每個tab處理主執行緒。
網路操作則由多個並列執行緒去執行,但數量也是受限的,一般在2-6個。
瀏覽器的主執行緒是一個無限的事件迴圈,而且一直保持程式alive,一直等著各種事件(例如繪畫事件,佈局事件),並處理他們。
瀏覽器渲染10問
1. 瀏覽器的組成部分是什麼?
2. 各個主流瀏覽器的渲染引起是什麼?
3. 瀏覽器顯示頁面的主要流程是什麼?
4. 您在做開發和測試時,有哪些瀏覽器(包括手機)存在相容性問題較多?
遇見最多的是Samsung手機和Huawei手機,有時一個相容性需要花費大量時間去調研和修復,可能是Samsung和Huawei定製的太厲害了,不相容一些特性吧。
5. 渲染引擎是單執行緒還是多執行緒?
6. 瀏覽器的網路操作一般由幾個執行緒去執行?
7. DOM樹,渲染樹是什麼?
8. 為了獲得更好的使用者體驗,我們應該在頁面做些什麼改進?
9. 瀏覽器是如何開啟PDF,Word等文件的?
10. 如果讓你開發一個瀏覽器,設計思路有哪些?
Web優化
我們知道,人的耐心是有限的,一個頁面如果超過8s,人基本上不會等了,這會對業務產生巨大影響。我們該如何去優化頁面呢?
思路很簡單,就是按照我們前面介紹的幾大步驟去優化。我們先回顧一下幾大步驟:
1. DNS查詢
2. TCP連線
3. 傳送HTTP請求
4. Server處理HTTP請求並返回HTTP報文
5. 瀏覽器解析並render頁面
6. HTTP連線斷開
當我想總結一下的時候,雅虎在10多年就總結出來一些經驗,參看這裡(https://developer.yahoo.com/performance/rules.html)。
這是10多年前的經驗,隨著科技的發展,一些新的經驗又出現了,可以容易想到的是:
1. 儘量將server離使用者近一些,例如人處在中國訪問Apple,應該是Apple中國站提供服務,GSLB很重要。
2. 不要把layout嵌入一層又一層,簡單說就是巢狀別太深,不然影響解析和渲染效能。
3. 有些資料可以在後臺處理的,就不要在前端通過JavaScript處理了。
4. 如果請求過大,Load Balance這些手段還是要上的。
5. 保持HTTP連線,合理設定Connection。
6. 後臺事件效能要高,能夠及時將結果返回給使用者。
當然涉及到高可用,高效能等那是另外一個話題。
總結
這道面試題非常經典,考察的知識非常豐富,跨度較大,如果沒有幾年的經驗,是很難完全掌握的,所以想答好其實不容易的。對這個問題,基本上可以根據我的經驗回答,也算是對這些年來在這方面的知識的一個總結。但同時,我也參考了一些資料,感謝他們。在參考的地方,我都把URL列出來了。
寫這篇文章耗費了大量時間,我覺得挺有意義,但是也不能保證裡面的內容全都是正確或準確的,如果您有任何問題可以通過以下方式聯絡我,以便我進一步改正並更新。
個人微信:terryisme 公眾號:terrymemo
下載
寫到這裡,三部分已經寫完,在這裡放上全文的PDF文件供大家參考,可能後面會更改,如果有新的文件,我將保持更新。