在面試過程中,我們可能都遇到過這個問題,如果我們不是很理解整個過程,可能覺得就是客戶端傳送請求,服務端處理請求這個簡單的過程。但是在工作中,我發現對這個問題理解的深度能讓你更快且精確的定位到的問題的所在,最起碼能知道是不是我們服務端的問題,接下來小生姑且根據目前自己的理解和參考資料對過程進行梳理。傳送http請求
路由**和路由選擇
nginx反向**
伺服器處理請求
參考dns解析網域名稱
我們都知道http/https是基於tcp的應用層協議,他們其實對主機是不敏感的,但是其底層的tcp對主機是敏感的:tcp需要乙個ip位址來唯一標識乙個目的主機。我們在瀏覽器瀏覽時,通常都是輸入www.***.com網域名稱,我們需要的ip從何而來呢?這就要歸功於dns網域名稱解析了。
dns解析網域名稱的原理其實就是建立了《網域名稱, ip>
的乙個對映關係,這個對映關係可能儲存在dns伺服器中,也可能在本地hosts檔案中。當你在瀏覽器輸入www.baidu.com,主機會先對本地hosts檔案進行查詢,如果存在對映,則直接使用hosts檔案中對映的ip位址;否則請求dns伺服器。一般後端都是使用nginx反向****請求到集群,所以一般我們網域名稱都是直接繫結nginx伺服器,然後通過nginx管理集群列表。
在linux和unix下我們可以用dig utility來查詢dns的相關資訊。
dig baidu.com
發起連線
三次握手
tcp的三次握手和四次揮手可以說是老生常談的話題了,這裡姑且羅列三次握手的過程:
三次握手也涉及了tcp的很多關鍵知識,seq:快取亂序報文、進行報文排序、防重放攻擊等,ack:確認和重發實現的可靠傳輸連線,具體內容參考:《計算機網路:自頂向下方法》第三章 運輸層
如果是https,還需要在三次握手之後協商ssl/tls會話引數,再次不詳述。
傳送http請求
建立tcp連線之後,傳送http報文。
路由**和路由選擇
報文從客戶端主機傳送出來後,是怎麼來到服務端主機的呢?這部分就是要說明這個問題。
我們每個ip都隸屬於乙個子網,如果客戶機和服務主機都是在同一子網內,直接在子網內廣播即可。但是,更多的是兩個ip不是同一子網的情況,這就需要通過路由器進行子網之間的**。
我們可以看到,路由**是通過乙個**表實現的。那怎麼得到**表呢?靜態配置或者自學習。靜態配置就是通過路由器後台將子網掩碼繫結到某個介面上。自學習是路由器會自動記錄通過該路由器的ip報文的路由選擇就是選擇**目前ip位址的下一跳的位址,網路拓撲結構建模之後就是乙個帶權無向圖,所以圖的最短路徑演算法在網路拓撲中就是乙個應用。路由選擇演算法按照是否需要全域性路由資訊分為分布式和集中式,分布式就是每台路由器監聽相鄰路由器的路徑變化,每次變化執行一次dijstra演算法,當相鄰路由器路徑沒有變化時,演算法結束;集中式的路由選擇演算法要求每台路由器廣播並收集所有的路由表資訊,然後執行最短路徑演算法進行計算。具體內容參見:《計算機網路:自頂向下方法》第四章 網路層
nginx反向**
首先我們需要理解什麼是**?假設我們要在北京租個小單間,按照傳統的方式,我們(客戶端)需要找到房東(伺服器),然後租房(執行),得到一間單間。而現在呢?很多的房間資訊都會託管到乙個中介平台(**)上,在比如自如這種中介平台(nginx**)上,我們租房只需要跟中介平台進行溝通簽訂合同然後得到一間單間這個結果。是否感覺其實**過程也差不多?其實不然,我們提到「很多的房間資訊都會託管到乙個中介平台(**)上」,這些房間類似於伺服器,集群都放到**中統一管理,能更好地做負載均衡、請求**等操作。
**分為反向**和正向**,其實這個是相對於客戶端來說的,如果客戶端需要配置**伺服器(比如vpn),客戶端同時知道真實的伺服器位址,這就是正向**,而反向**,客戶端只知道**伺服器,只需要訪問**伺服器就能拿到結果。
當我們拿到乙個網域名稱www.abc.com時,如果服務端為集群時,其實這個網域名稱是nginx伺服器的網域名稱,只是通過nginx將請求負載均衡到不同主機上。
高可用nginx
dns負載均衡
dns負載均衡起來在外網上是用的比較少的,因為dns的負載均衡可控性比較低,一般是使用輪詢的方式。其原理就是在解析網域名稱的時候將其解析成不同的ip,然後去訪問不同的主機。
該結構是目前高可用nginx的經典實現方案,主要是使用keepalived通過vrrp協議,實現了主從熱備。
伺服器處理請求
解析http請求
解析http請求就是伺服器的事情了,
跨域請求檢測和處理
首先我們需要理解跨域的含義,我們參考spring基於實現的corsutils#iscorrequest,跨域請求其實就是請求中origin首部攜帶的url中和當前請求的主機不匹配(schema、host、port有乙個或乙個以上不匹配),比如origin:
,我們呼叫的api為:,顯然
和
,還需要注意的是schema不同也屬於跨域,比如
和
。還有一種比較容易忽略的情況就是通過ip訪問和通過網域名稱訪問這種情況也會判定為跨域。
我們首先需要認識幾個關於cors的首部:
客戶端請求攜帶:
服務端響應攜帶:
如果客戶端沒有設定withcredentials=true
,瀏覽器將不會攜帶cookie;服務端響應中不包含access-control-allow-credentials: true
,請求是成功的,但是瀏覽器會攔截結果,所以前端最終還是無法獲取到結果。
這裡有幾個關於跨域知識的比較權威的講解的**:
#******-cross-origin-request
spring中的corsfilter
其實是參考w3c標準實現的,可以學習使用。
選擇處理方法並響應
springdispatcherservlet#dodispatch
邏輯,詳見:
參考阿里雲負載均衡文件
Web頁面請求過程原理
web 頁面請求過程 1.dhcp 配置主機資訊 假設主機最開始沒有 ip 位址以及其它資訊,那麼就需要先使用 dhcp 來獲取。主機生成乙個 dhcp 請求報文,並將這個報文放入具有目的埠 67 和源埠 68 的 udp 報文段中。該報文段則被放入在乙個具有廣播 ip 目的位址 255.255.2...
Web請求過程
當使用者在瀏覽器中輸入乙個url 如www.baidu.com 進行網頁瀏覽時,將會發生一系列的操作。大致流程如下 1 網域名稱解析 當使用者輸入網域名稱後,需要將網域名稱轉換成正確的ip位址,才能夠訪問web伺服器。首先會查詢本地網域名稱hosts檔案,若存在對應網域名稱的ip位址,就直接使用。若...
WEB請求過程
一 乙個例子 當使用者在瀏覽器中輸入www.com這個url時,首先,dns會把這個網域名稱解析成ip位址,然後根據這個ip找到對應的伺服器,並發起乙個get請求,對於伺服器端而言,可能會有負載均衡裝置來平均分配使用者請求,而請求的資料可能在分布式快取裡,靜態檔案中,或是資料庫中,當資料返回給瀏覽器...