當咱們開始在瀏覽器中輸入網址的時候,瀏覽器其實就已經在智能的匹配可能得 url 了,他會從歷史記錄,書籤等地方,找到已經輸入的字符串可能對應的 url,而後給出智能提示,讓你能夠補全url地址。對於 google的chrome 的瀏覽器,他甚至會直接從緩存中把網頁展現出來,就是說,你尚未按下 enter,頁面就出來了。php
DNS解析的過程就是尋找哪臺機器上有你須要資源的過程。當你在瀏覽器中輸入一個地址時,例如http://www.baidu.com,其實不是百度網站真正意義上的地址。互聯網上每一臺計算機的惟一標識是它的IP地址,可是IP地址並不方便記憶。用戶更喜歡用方便記憶的網址去尋找互聯網上的其它計算機,也就是上面提到的百度的網址。因此互聯網設計者須要在用戶的方便性與可用性方面作一個權衡,這個權衡就是一個網址到IP地址的轉換,這個過程就是DNS解析。html
解析過程:前端
一、查找瀏覽器緩存:由於瀏覽器通常會緩存DNS記錄一段時間,不一樣瀏覽器的時間可能不同,通常2-30分鐘不等,瀏覽器去查找這些緩存,若是有緩存,直接返回IP,不然下一步。web
二、查找系統緩存:瀏覽器緩存中找不到IP以後,瀏覽器會查看本地硬盤的 hosts 文件,看看其中有沒有和這個域名對應的規則,若是有的話就直接使用 hosts 文件裏面的 ip 地址。chrome
三、若是在本地的 hosts 文件沒有可以找到對應的 ip 地址,瀏覽器會發出一個 DNS請求到本地DNS服務器 。數據庫
四、查詢你輸入的網址的DNS請求到達本地DNS服務器以後,本地DNS服務器會首先查詢它的緩存記錄,若是緩存中有此條記錄,就能夠直接返回結果,此過程是遞歸的方式進行查詢。若是沒有,本地DNS服務器還要向DNS根服務器進行查詢。編程
五、根DNS服務器沒有記錄具體的域名和IP地址的對應關係,而是告訴本地DNS服務器,你能夠到域服務器上去繼續查詢,並給出域服務器的地址。這種過程是迭代的過程。json
六、本地DNS服務器繼續向域服務器發出請求,在這個例子中,請求的對象是.com域服務器。.com域服務器收到請求以後,也不會直接返回域名和IP地址的對應關係,而是告訴本地DNS服務器,你的域名的解析服務器的地址。segmentfault
七、最後,本地DNS服務器向域名的解析服務器發出請求,這時就能收到一個域名和IP地址對應關係,本地DNS服務器不只要把IP地址返回給用戶電腦,還要把這個對應關係保存在緩存中,以備下次別的用戶查詢時,能夠直接返回結果,加快網絡訪問。後端
知識擴展:
1)什麼是DNS?
DNS(Domain Name System,域名系統),因特網上做爲域名和IP地址相互映射的一個分佈式數據庫,可以使用戶更方便的訪問互聯網,而不用去記住可以被機器直接讀取的IP數串。經過主機名,最終獲得該主機名對應的IP地址的過程叫作域名解析(或主機名解析)。
通俗的講,咱們更習慣於記住一個網站的名字,好比www.baidu.com,而不是記住它的ip地址,好比:167.23.10.2。而計算機更擅長記住網站的ip地址,而不是像www.baidu.com等連接。由於,DNS就至關於一個電話本,好比你要找www.baidu.com這個域名,那我翻一翻個人電話本,我就知道,哦,它的電話(ip)是167.23.10.2。
2)DNS查詢的兩種方式:遞歸查詢和迭代查詢
一、遞歸解析 當局部DNS服務器本身不能回答客戶機的DNS查詢時,它就須要向其餘DNS服務器進行查詢。此時有兩種方式,如圖所示的是遞歸方式。局部DNS服務器本身負責向其餘DNS服務器進行查詢,通常是先向該域名的根域服務器查詢,再由根域名服務器一級級向下查詢。最後獲得的查詢結果返回給局部DNS服務器,再由局部DNS服務器返回給客戶端。
二、迭代解析 當局部DNS服務器本身不能回答客戶機的DNS查詢時,也能夠經過迭代查詢的方式進行解析,如圖所示。局部DNS服務器不是本身向其餘DNS服務器進行查詢,而是把能解析該域名的其餘DNS服務器的IP地址返回給客戶端DNS程序,客戶端DNS程序再繼續向這些DNS服務器進行查詢,直到獲得查詢結果爲止。也就是說,迭代解析只是幫你找到相關的服務器而已,而不會幫你去查。3)DNS域名稱空間的組織方式
咱們在前面有說到根DNS服務器,域DNS服務器,這些都是DNS域名稱空間的組織方式。按其功能命名空間中用來描述DNS域名稱的五個類別的介紹詳見下表中,以及與每一個名稱類型的示例
4)DNS負載均衡
當一個網站有足夠多的用戶的時候,假如每次請求的資源都位於同一臺機器上面,那麼這臺機器隨時可能會蹦掉。處理辦法就是用DNS負載均衡技術,它的原理是在DNS服務器中爲同一個主機名配置多個IP地址,在應答DNS查詢時,DNS服務器對每一個查詢將以DNS文件中主機記錄的IP地址按順序返回不一樣的解析結果,將客戶端的訪問引導到不一樣的機器上去,使得不一樣的客戶端訪問不一樣的服務器,從而達到負載均衡的目的。例如能夠根據每臺機器的負載量,該機器離用戶地理位置的距離等等。
在拿到域名對應的IP地址後,會以隨機端口(1024~~65535)向WEB服務器程序80端口發起TCP的鏈接請求,這個鏈接請求進入到內核的TCP/IP協議棧(用於識別該鏈接請求,解封包,一層一層的剝開),還有可能要通過Netfilter防火牆(屬於內核的模塊)的過濾,最終到達WEB程序,最終創建了TCP/IP的鏈接,對於客戶端與服務器的TCP連接,必然要說的就是『三次握手』。
TCP三次握手:第一次握手:客戶端將標誌位SYN置爲1,隨機產生一個值爲seq=J(J的取值範圍爲=1234567)的數據包到服務器,客戶端進入SYN_SENT狀態,等待服務端確認;
第二次握手:服務端收到數據包後由標誌位SYN=1知道客戶端請求創建鏈接,服務端將標誌位SYN和ACK都置爲1,ack=J+1,隨機產生一個值seq=K,並將該數據包發送給客戶端以確認鏈接請求,服務端進入SYN_RCVD狀態。
第三次握手:客戶端收到確認後,檢查ack是否爲J+1,ACK是否爲1,若是正確則將標誌位ACK置爲1,ack=K+1,並將該數據包發送給服務端,服務端檢查ack是否爲K+1,ACK是否爲1,若是正確則鏈接創建成功,完成三次握手,隨後客戶端A與服務端B之間能夠開始傳輸數據了。
通俗化以後就是:
客戶端:老弟我要跟你連接
服務端:好的,贊成了
客戶端:好嘞
知識拓展:
1)爲何須要三次握手:
《計算機網絡》第四版中講「三次握手」的目的是「爲了防止已失效的鏈接請求報文段忽然又傳送到了服務端,於是產生錯誤」
書中的例子是這樣的,「已失效的鏈接請求報文段」的產生在這樣一種狀況下:client發出的第一個鏈接請求報文段並無丟失,而是在某個網絡結點長時間的滯留了,以至延誤到鏈接釋放之後的某個時間纔到達server。原本這是一個早已失效的報文段。但server收到此失效的鏈接請求報文段後,就誤認爲是client再次發出的一個新的鏈接請求。因而就向client發出確認報文段,贊成創建鏈接。
假設不採用「三次握手」,那麼只要server發出確認,新的鏈接就創建了。因爲如今client並無發出創建鏈接的請求,所以不會理睬server的確認,也不會向server發送數據。但server卻覺得新的運輸鏈接已經創建,並一直等待client發來數據。這樣,server的不少資源就白白浪費掉了。採用「三次握手」的辦法能夠防止上述現象發生。例如剛纔那種狀況,client不會向server的確認發出確認。server因爲收不到確認,就知道client並無要求創建鏈接。」。主要目的防止server端一直等待,浪費資源。
其實這部分又能夠稱爲前端工程師眼中的HTTP,它主要發生在客戶端。發送HTTP請求的過程就是構建HTTP請求報文並經過TCP協議中發送到服務器指定端口(HTTP協議80/8080, HTTPS協議443)。HTTP請求報文是由三部分組成: 請求行, 請求報頭和請求正文。
請求行
格式以下:
Method Request-URL HTTP-Version CRLF
eg: GET index.html HTTP/1.1
經常使用的方法有: GET, POST, PUT, DELETE, OPTIONS, HEAD。
請求報頭
請求報頭容許客戶端向服務器傳遞請求的附加信息和客戶端自身的信息。 PS: 客戶端不必定特指瀏覽器,有時候也可以使用Linux下的CURL命令以及HTTP客戶端測試工具等。 常見的請求報頭有: Accept, Accept-Charset, Accept-Encoding, Accept-Language, Content-Type, Authorization, Cookie, User-Agent等。
上圖是使用Chrome開發者工具截取的對百度的HTTP請求以及響應報文,從圖中能夠看出,請求報頭中使用了Accept, Accept-Encoding, Accept-Language, Cache-Control, Connection, Cookie等字段。Accept用於指定客戶端用於接受哪些類型的信息,Accept-Encoding與Accept相似,它用於指定接受的編碼方式。Connection設置爲Keep-alive用於告訴客戶端本次HTTP請求結束以後並不須要關閉TCP鏈接,這樣可使下次HTTP請求使用相同的TCP通道,節省TCP鏈接創建的時間。請求正文
當使用POST, PUT等方法時,一般須要客戶端向服務器傳遞數據。這些數據就儲存在請求正文中。在請求包頭中有一些與請求正文相關的信息,例如: 如今的Web應用一般採用Rest架構,請求的數據格式通常爲json。這時就須要設置Content-Type: application/json。
服務器給瀏覽器響應一個301永久重定向響應,這樣瀏覽器就會訪問「www.google.com/」 而非「google.com/」。
爲何服務器必定要重定向而不是直接發送用戶想看的網頁內容呢?其中一個緣由跟搜索引擎排名有關。若是一個頁面有兩個地址,就像http://www.yy.com/和http://yy.com/,搜索引擎會認爲它們是兩個網站,結果形成每一個搜索連接都減小從而下降排名。而搜索引擎知道301永久重定向是什麼意思,這樣就會把訪問帶www的和不帶www的地址歸到同一個網站排名下。還有就是用不一樣的地址會形成緩存友好性變差,當一個頁面有好幾個名字時,它可能會在緩存裏出現好幾回。
知識擴展
1)301和302的區別。
301和302狀態碼都表示重定向,就是說瀏覽器在拿到服務器返回的這個狀態碼後會自動跳轉到一個新的URL地址,這個地址能夠從響應的Location首部中獲取(用戶看到的效果就是他輸入的地址A瞬間變成了另外一個地址B)——這是它們的共同點。
他們的不一樣在於。301表示舊地址A的資源已經被永久地移除了(這個資源不可訪問了),搜索引擎在抓取新內容的同時也將舊的網址交換爲重定向以後的網址;
302表示舊地址A的資源還在(仍然能夠訪問),這個重定向只是臨時地從舊地址A跳轉到地址B,搜索引擎會抓取新的內容而保存舊的網址。 SEO302好於301
2)重定向緣由:
一、網站調整(如改變網頁目錄結構);
二、網頁被移到一個新地址;
三、網頁擴展名改變(如應用須要把.php改爲.Html或.shtml)。 這種狀況下,若是不作重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶獲得一個404頁面錯誤信息,訪問流量白白喪失;再者某些註冊了多個域名的網站,也須要經過重定向讓訪問這些域名的用戶自動跳轉到主站點等。
3)何時進行301或者302跳轉呢?
當一個網站或者網頁24—48小時內臨時移動到一個新的位置,這時候就要進行302跳轉,而使用301跳轉的場景就是以前的網站由於某種緣由須要移除掉,而後要到新的地址訪問,是永久性的。
清晰明確而言:使用301跳轉的大概場景以下:
一、域名到期不想續費(或者發現了更適合網站的域名),想換個域名。
二、在搜索引擎的搜索結果中出現了不帶www的域名,而帶www的域名卻沒有收錄,這個時候能夠用301重定向來告訴搜索引擎咱們目標的域名是哪個。
通過前面的重重步驟,咱們終於將咱們的http請求發送到了服務器這裏,其實前面的重定向已是到達服務器了,那麼,服務器是如何處理咱們的請求的呢?
後端從在固定的端口接收到TCP報文開始,它會對TCP鏈接進行處理,對HTTP協議進行解析,並按照報文格式進一步封裝成HTTP Request對象,供上層使用。
一些大一點的網站會將你的請求到反向代理服務器中,由於當網站訪問量很是大,網站愈來愈慢,一臺服務器已經不夠用了。因而將同一個應用部署在多臺服務器上,將大量用戶的請求分配給多臺機器處理。此時,客戶端不是直接經過HTTP協議訪問某網站應用服務器,而是先請求到Nginx,Nginx再請求應用服務器,而後將結果返回給客戶端,這裏Nginx的做用是反向代理服務器。同時也帶來了一個好處,其中一臺服務器萬一掛了,只要還有其餘服務器正常運行,就不會影響用戶使用。
經過Nginx的反向代理,咱們到達了web服務器,服務端腳本處理咱們的請求,訪問咱們的數據庫,獲取須要獲取的內容等等,固然,這個過程涉及不少後端腳本的複雜操做
知識拓展
1)什麼是反向代理?
客戶端原本能夠直接經過HTTP協議訪問某網站應用服務器,網站管理員能夠在中間加上一個Nginx,客戶端請求Nginx,Nginx請求應用服務器,而後將結果返回給客戶端,此時Nginx就是反向代理服務器。
天然而然這部分對應的就是後端工程師眼中的HTTP。後端從在固定的端口接收到TCP報文開始,這一部分對應於編程語言中的socket。它會對TCP鏈接進行處理,對HTTP協議進行解析,並按照報文格式進一步封裝成HTTP Request對象,供上層使用。這一部分工做通常是由Web服務器去進行,我使用過的Web服務器有Tomcat, Jetty和Netty等等。
HTTP響應報文也是由三部分組成: 狀態碼, 響應頭和響應報文。
狀態碼
狀態行由協議版本、數字形式的狀態代碼、及相應的狀態描述,各元素之間以空格分隔。
格式: HTTP-Version Status-Code Reason-Phrase CRLF
例如: HTTP/1.1 200 OK \r\n
-- 協議版本:是用http1.0仍是其餘版本
-- 狀態描述:狀態描述給出了關於狀態代碼的簡短的文字描述。好比狀態代碼爲200時的描述爲 ok
-- 狀態代碼:狀態代碼由三位數字組成,第一個數字定義了響應的類別,且有五種可能取值。以下
1xx:信息性狀態碼,表示服務器已接收了客戶端請求,客戶端可繼續發送請求。
100 Continue
101 Switching Protocols
2xx:成功狀態碼,表示服務器已成功接收到請求並進行處理。
200 OK 表示客戶端請求成功
204 No Content 成功,但不返回任何實體的主體部分
206 Partial Content 成功執行了一個範圍(Range)請求
3xx:重定向狀態碼,表示服務器要求客戶端重定向。
301 Moved Permanently 永久性重定向,響應報文的Location首部應該有該資源的新URL
302 Found 臨時性重定向,響應報文的Location首部給出的URL用來臨時定位資源
303 See Other 請求的資源存在着另外一個URI,客戶端應使用GET方法定向獲取請求的資源
304 Not Modified 服務器內容沒有更新,能夠直接讀取瀏覽器緩存
307 Temporary Redirect 臨時重定向。與302 Found含義同樣。302禁止POST變換爲GET,但實際使用時並不必定,307則更多瀏覽器可能會遵循這一標準,但也依賴於瀏覽器具體實現
4xx:客戶端錯誤狀態碼,表示客戶端的請求有非法內容。
400 Bad Request 表示客戶端請求有語法錯誤,不能被服務器所理解
401 Unauthonzed 表示請求未經受權,該狀態代碼必須與 WWW-Authenticate 報頭域一塊兒使用
403 Forbidden 表示服務器收到請求,可是拒絕提供服務,一般會在響應正文中給出不提供服務的緣由
404 Not Found 請求的資源不存在,例如,輸入了錯誤的URL
5xx:服務器錯誤狀態碼,表示服務器未能正常處理客戶端的請求而出現意外錯誤。
500 Internel Server Error 表示服務器發生不可預期的錯誤,致使沒法完成客戶端的請求
503 Service Unavailable 表示服務器當前不可以處理客戶端的請求,在一段時間以後,服務器可能會恢復正常
響應頭
響應頭部:由關鍵字/值對組成,每行一對,關鍵字和值用英文冒號":"分隔,典型的響應頭有:
響應報文
包含着咱們須要的一些具體信息,好比cookie,html,image,後端返回的請求數據等等。這裏須要注意,響應正文和響應頭之間有一行空格,表示響應頭的信息到空格爲止,下圖是fiddler抓到的請求正文,紅色框中的:響應正文:
在瀏覽器沒有完整接受所有HTML文檔時,它就已經開始顯示這個頁面了,瀏覽器是如何把頁面呈如今屏幕上的呢?不一樣瀏覽器可能解析的過程不太同樣,這裏咱們只介紹webkit的渲染過程,下圖對應的就是WebKit渲染的過程,這個過程包括:
解析html以構建dom樹 -> 構建render樹 -> 佈局render樹 -> 繪製render樹
瀏覽器在解析html文件時,會」自上而下「加載,並在加載過程當中進行解析渲染。在解析過程當中,若是遇到請求外部資源時,如圖片、外鏈的CSS、iconfont等,請求過程是異步的,並不會影響html文檔進行加載。
解析過程當中,瀏覽器首先會解析HTML文件構建DOM樹,而後解析CSS文件構建渲染樹,等到渲染樹構建完成後,瀏覽器開始佈局渲染樹並將其繪製到屏幕上。這個過程比較複雜,涉及到兩個概念: reflow(迴流)和repain(重繪)。
DOM節點中的各個元素都是以盒模型的形式存在,這些都須要瀏覽器去計算其位置和大小等,這個過程稱爲relow;當盒模型的位置,大小以及其餘屬性,如顏色,字體,等肯定下來以後,瀏覽器便開始繪製內容,這個過程稱爲repain。好比:display:none 會觸發迴流,而 visibility:hidden 只會觸發重繪。
頁面在首次加載時必然會經歷reflow和repain。reflow和repain過程是很是消耗性能的,尤爲是在移動設備上,它會破壞用戶體驗,有時會形成頁面卡頓。因此咱們應該儘量少的減小reflow和repain。
當文檔加載過程當中遇到js文件,html文檔會掛起渲染(加載解析渲染同步)的線程,不只要等待文檔中js文件加載完畢,還要等待解析執行完畢,才能夠恢復html文檔的渲染線程。由於JS有可能會修改DOM,最爲經典的document.write,這意味着,在JS執行完成前,後續全部資源的下載多是沒有必要的,這是js阻塞後續資源下載的根本緣由。因此咱們平時的代碼中,js是放在html文檔末尾的。
JS的解析是由瀏覽器中的JS解析引擎完成的,好比谷歌的是V8。JS是單線程運行,也就是說,在同一個時間內只能作一件事,全部的任務都須要排隊,前一個任務結束,後一個任務才能開始。可是又存在某些任務比較耗時,如IO讀寫等,因此須要一種機制能夠先執行排在後面的任務,這就是:同步任務(synchronous)和異步任務(asynchronous)。
JS的執行機制就能夠看作是一個主線程加上一個任務隊列(task queue)。同步任務就是放在主線程上執行的任務,異步任務是放在任務隊列中的任務。全部的同步任務在主線程上執行,造成一個執行棧;異步任務有了運行結果就會在任務隊列中放置一個事件;腳本運行時先依次運行執行棧,而後會從任務隊列裏提取事件,運行任務隊列中的任務,這個過程是不斷重複的,因此又叫作事件循環(Event loop)。
TCP四次揮手:
第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。
第二次揮手:Server收到FIN後,發送一個ACK給Client,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。
第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。
第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號爲收到序號+1,Server進入CLOSED狀態,完成四次揮手。
上圖能夠通俗化:
客戶端:老弟,我這邊沒數據要傳了,我們關閉連接吧
服務端:好的,接收到了,我看看我這邊還有沒有要傳的
服務端:我這邊也沒有了,關閉吧
客戶端:好嘞
知識拓展
1)爲何創建鏈接是三次握手,而關閉鏈接倒是四次揮手呢?
這是由於服務端在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。而關閉鏈接時,當收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,己方也未必所有數據都發送給對方了,因此己方能夠當即close,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送。
參考連接:
segmentfault.com/a/119000000… www.cnblogs.com/yuanzhiguo/… www.cnblogs.com/duhuo/p/517… zhuanlan.zhihu.com/p/78677852