天天看點

阿裡面試題:“說一下從 url 輸入到傳回請求的過程”

作者:JAVA後端架構
阿裡面試題:“說一下從 url 輸入到傳回請求的過程”

前言

此文章是關于浏覽器的常見問題,大概面試10家遇到6家提問類似問題(主要是大廠和中廠)。(面試的部分内容已經忘了,為了串聯成一個完整的故事,增加可讀性,20%的内容為虛構),目前入職滴滴出行成都團隊。

問題: 從浏覽器位址欄輸入url到請求傳回發生了什麼

你一看這種爛掉牙的問題,小case,但996面試大佬由此延展的問題已經遠遠超越了這個問題本身了,不信你就接着看。

我回答了首先會進行 url 解析,根據 dns 系統進行 ip 查找。

話音剛落,此時一位喜歡修福報的公司的大佬打斷了我,說url為啥要解析,dns查詢規則是什麼?我一聽就心裡想,不按套路出牌啊,網上一般都沒問這兩個問題,心裡再一想,俗話說,萬事開頭難,扛過這一波,答出來,就是陽光明媚,萬物騷動的春天!

先說為什麼url要解析(也就是編碼)

  • 我回答大概内容是:因為網絡标準規定了URL隻能是字母和數字,還有一些其它特殊符号(-_.~ ! * ' ( ) ; : @ & = + $ , / ? # [ ],特殊符号是我下來查的資料,實在背不住這麼多,比較常見的就是不包括百分号和雙引号),而且如果不轉義會出現歧義,比如http:www.baidu.com?key=value,假如我的key本身就包括等于=符号,比如ke=y=value,就會出現歧義,你不知道=到底是連接配接key和value的符号,還是說本身key裡面就有=。
  • 大佬接着毒打我說,那url編碼的規則是什麼呢,我說utf-8
  • 大佬接着窮追不舍,為啥是utf-8呢,所有浏覽器都是這樣嗎?中文的話用gb2312編碼嗎,還有就是萬一浏覽器不是你說的這樣統一用utf-8,你怎麼保證都是utf-8的編碼?
  • 我支支吾吾的說,我了解的大概是這樣,不太清楚, 應該和html本身的編碼格式有關,然後怎麼保證utf-8的編碼,我覺得可以用encodeURIComponent
  • 大佬說encodeURIComponent比encodeURI有什麼差別?
  • 差別就是encodeURIComponent編碼範圍更廣,适合給參數編碼,encodeURI适合給URL本身(locaion.origin)編碼,當然項目裡一般都是用qs庫去處理

然後說說dns解析流程,并且html如何做dns優化

首先dns這個屬于很久以前在計算機網絡謝希仁版看到過了,有一些細節忘了,但是大緻流程是記得的。比如說查詢一個網址為:www.baidu.com

1、器中輸入www.baidu.com域名,作業系統會先查hosts件是否有記錄,有的話就會把相對應映射的IP傳回。

2、hosts檔案沒有就去查本地dns解析器有沒有緩存。(這個我沒答上來)

3、然後就去找我們計算機上配置的dns伺服器上有或者有緩存,就傳回

4、還沒有的話就去找根DNS伺服器(全球13台,固定ip位址),然後判斷.com域名是哪個伺服器管理,如果無法解析,就查找.baidu.com伺服器是否能解析,直到查到www.baidu.com的IP位址

注:後面查資料才發現dns查詢有兩種模式,一種是轉發模式,一種是非轉發模式,我上面說的4是非轉發模式。

前端的dns優化,可以在html頁面頭部寫入dns緩存位址,比如

<meta http-equiv="x-dns-prefetch-control" content="on" />
<link rel="dns-prefetch" href="http://bdimg.share.baidu.com" />
           

終于抗過了第一輪的猛問,接着我繼續說從浏覽器位址欄輸入url到請求傳回發生了什麼

查找到IP之後,就是http協定的三次握手(以及後面會涉及到四次分手)

我剛恢複節奏,準備侃侃而談,修福報的大佬再次打斷了我,說三次握手,為啥兩次不行,順便說一下3次握手發生了什麼。

我去,大意了,沒有閃,這是不是說我每說一句都要夾雜着各種問題,太難了啊!!!

沒有辦法,繼續回答大佬,我說我先回答三次握手發生的事情吧,簡答來說:

  • 第一次握手:主機A發送位碼為SYN=1的TCP包給伺服器,并且随機産生一個作為确認号(這是tcp包的一部分),主機B收到SYN碼後直到A要求建立連接配接;
  • 第二次握手:主機B收到請求後,向A發送确認号(主機A的seq+1),syn=1,seq = 随機數 的TCP包;
  • 主機A收到後檢查确認号是否正确,即第一次A發送的确認号是否+1了,以及位碼ack是否為1,若正确,主機A會再發送确認号(主機B的seq+1),ack=1,主機B收到後确認seq值與ack=1則連接配接建立成功。

接着補上小問題為什麼兩次握手不行,因為第二次握手,主機B還不能确認主機A已經收到确認請求,也是說B認為建立好連接配接,開始發資料了,結果發出去的包一直A都沒收到,那攻擊B就很容易了,我專門發包不接收,伺服器很容易就挂了。

接着,大佬說出個加分題,我看你不是科班出身,能答多少是多少。問題是,從網卡把資料包傳輸出去到伺服器發生了什麼,提示我OSI參考模型

我一聽,好嘛,這不是計算機網絡的知識嗎,幸虧之前看過書,但也是好久以前看過了,隻能憑借自己的了解解答了。

  • 我說,先從區域網路把資料發送到公司的交換機(如果交換機沒有快取區域mac位址和IP位址的映射,此時會通過ARP協定來獲得),交換機的好處是可以隔離沖突域(因為以太網用的是CSMA/CD協定,這個協定規定網線上同一時刻隻能有一台機器發送資料),這樣就可以不僅僅同一時刻隻有一台機器發送網絡包了
  • 然後交換機再将資料發送到路由器,路由器相當于公司網關(我們公司小),路由器具有轉發和分組資料包的功能(路由器通過標明的路由協定會構造出路由表,同時不定期的跟相鄰路由器交換路由資訊),然後這算是經過了實體層,資料鍊路層(以太網),開始到網絡層進行資料轉發了
  • 然後路由器轉發IP資料報,一般公司的IP位址都會經過NAT轉換,讓内網的ip也能夠通路外網,我們公司我注意了一下是192.168打頭的内網ip位址。通過路由器的分組傳輸,所有資料到達伺服器。
  • 然後伺服器的上層協定傳輸層協定開始發揮作用,根據tcp包裡的端口号,讓伺服器特定的服務來處理到來的資料包,并且tcp是面向位元組流的(tcp有四大特性,可靠傳輸、流量控制、擁塞控制、連接配接管理),是以我們node的request對象,它的監聽事件data事件為什麼要用字元串一起拼接起來呢(buffer),就是因為tcp本身就是位元組流,request對象使用的data(http層面)是tcp傳來的資料塊。
  • 最後資料由傳輸層轉交給應用層,也就是http服務(或者https),後端經過一系列邏輯處理,傳回給前端資料。

答完這裡,我說大佬我隻知道大概的流程,具體細節我不是很清楚,但自己後面會補上。。。

大佬讓我繼續,我就接着3次握手之後接着說道,建立完連結,就該請求html檔案了,如果html檔案在緩存裡面浏覽器直接傳回,如果沒有,就去背景拿

剛說到緩存,立馬就有一種不詳的預感,果不其然大佬先讓把緩存解釋一下。緩存這種問爛的問題,本以為能輕松應對,結果還是被問了個滿頭包。。。。

阿裡面試題:“說一下從 url 輸入到傳回請求的過程”

我說的大概意思是:

  • 浏覽器首次加載資源成功時,伺服器傳回200,此時浏覽器不僅将資源下載下傳下來,而且把response的header(裡面的date屬性非常重要,用來計算第二次相同資源時目前時間和date的時間差)一并緩存;
  • 下一次加載資源時,首先要經過強緩存的處理,cache-control的優先級最高,比如cache-control:no-cache,就直接進入到協商緩存的步驟了,如果cache-control:max-age=xxx,就會先比較目前時間和上一次傳回200時的時間差,如果沒有超過max-age,命中強緩存,不發請求直接從本地緩存讀取該檔案(這裡需要注意,如果沒有cache-control,會取expires的值,來對比是否過期),過期的話會進入下一個階段,協商緩存
  • 協商緩存階段,則向伺服器發送header帶有If-None-Match和If-Modified-Since的請求,伺服器會比較Etag,如果相同,命中協商緩存,傳回304;如果不一緻則有改動,直接傳回新的資源檔案帶上新的Etag值并傳回200;
  • 協商緩存第二個重要的字段是,If-Modified-Since,如果用戶端發送的If-Modified-Since的值跟伺服器端擷取的檔案最近改動的時間,一緻則命中協商緩存,傳回304;不一緻則傳回新的last-modified和檔案并傳回200;

果不其然,大佬問了一些緩存不常問的,首先就是問我知道什麼是from disk cache和from memory cache嗎,什麼時候會觸發?

  • 我說強緩存會觸發,這兩種,具體什麼行為不知道,大概内容如下:
1、先查找記憶體,如果記憶體中存在,從記憶體中加載;
2、如果記憶體中未查找到,選擇硬碟擷取,如果硬碟中有,從硬碟中加載;
3、如果硬碟中未查找到,那就進行網絡請求;
4、加載到的資源緩存到硬碟和記憶體;
           

接着大佬又問知道什麼是啟發式緩存嗎,在什麼條件下觸發?

這個問題給我的感覺就兩個字,懵逼!然後如實回答不知道。(查了下資料大概如下)

啟發式緩存:

如果響應中未顯示Expires,Cache-Control:max-age或Cache-Control:s-maxage,并且響應中不包含其他有關緩存的限制,緩存可以使用啟發式方法計算新鮮度壽命。通常會根據響應頭中的2個時間字段 Date 減去 Last-Modified 值的 10% 作為緩存時間。

// Date 減去 Last-Modified 值的 10% 作為緩存時間。
// Date:建立封包的日期時間, Last-Modified 伺服器聲明文檔最後被修改時間
  response_is_fresh =  max(0,(Date -  Last-Modified)) % 10
           

接着回答,我說傳回html之後,會解析html,這部分知識我提前準備過,但是答的不是很詳細,大概意思就是cssom + domTree = html,然後布局和繪制

  • 建構DOM樹(DOM tree):從上到下解析HTML文檔生成DOM節點樹(DOM tree),也叫内容樹(content tree);
  • 建構CSSOM(CSS Object Model)樹:加載解析樣式生成CSSOM樹;
  • 執行JavaScript:加載并執行JavaScript代碼(包括内聯代碼或外聯JavaScript檔案);
  • 建構渲染樹(render tree):根據DOM樹和CSSOM樹,生成渲染樹(render tree);
  • 渲染樹:按順序展示在螢幕上的一系列矩形,這些矩形帶有字型,顔色和尺寸等視覺屬性。
  • 布局(layout):根據渲染樹将節點樹的每一個節點布局在螢幕上的正确位置;
  • 繪制(painting):周遊渲染樹繪制所有節點,為每一個節點适用對應的樣式,這一過程是通過UI後端子產品完成;

接着面試官問我一些頁面渲染層的一些優化手段,大概如下:

頁面渲染優化

  • HTML文檔結構層次盡量少,最好不深于六層;
  • 腳本盡量後放,放在前即可;
  • 少量首屏樣式内聯放在标簽内;
  • 樣式結構層次盡量簡單;
  • 在腳本中盡量減少DOM操作,盡量緩存通路DOM的樣式資訊,避免過度觸發回流;
  • 減少通過JavaScript代碼修改元素樣式,盡量使用修改class名方式操作樣式或動畫;
  • 動畫盡量使用在絕對定位或固定定位的元素上;
  • 隐藏在螢幕外,或在頁面滾動時,盡量停止動畫;
  • 盡量緩存DOM查找,查找器盡量簡潔;
  • 涉及多域名的網站,可以開啟域名預解析

最後面試官問我,如何診斷頁面渲染時各個性能名額,我大概說了,通過chrome浏覽器的工具,比如看網絡請求情況的network,還有看頁面渲染情況的perfermance,面試下來自己查了一些資料,我打算以後有機會自己總結一篇。

為幫助開發者們提升面試技能、有機會入職BATJ等大廠公司,特别制作了這個專輯——這一次整體放出。

大緻内容包括了: Java 集合、JVM、多線程、并發程式設計、設計模式、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat等大廠面試題等、等技術棧!

阿裡面試題:“說一下從 url 輸入到傳回請求的過程”

歡迎大家關注公衆号【Java爛豬皮】,回複【666】,擷取以上最新Java後端架構VIP學習資料以及視訊學習教程,然後一起學習,一文在手,面試我有。

每一個專欄都是大家非常關心,和非常有價值的話題,如果我的文章對你有所幫助,還請幫忙點贊、好評、轉發一下,你的支援會激勵我輸出更高品質的文章,非常感謝!

阿裡面試題:“說一下從 url 輸入到傳回請求的過程”

繼續閱讀