標籤:

輸入URL後到底發生了什麼?我用小白能明白的方式來說說!

背景:

1. 本人非科班,非IT/互聯網行業從業人員,本文僅從較高層級的角度進行簡單總結,涉及底層實現的內容盡量不提及,以免誤人子弟。我盡量用淺顯易懂的方式把問題說明白。如果有疏漏出錯的地方,希望各位大神不吝賜教。各位有不明白的地方儘管找我交流。

2.涉及後端的代碼都是用Python寫的,只是用來輔助說明,沒必要理解

3.內容均憑已有知識進行歸納總結,僅mvc的定義參考了一下維基百科,圖是用

ProcessOn 畫的。

4.學前端的同學,只想了解一下MVC的同學,請從「我的博客是怎麼部署的」開始看。

一、 基本概念

  1. 什麼是域名?什麼是主機?什麼是主機名?

    我們已經對域名習以為常了,你可能會說www.sina.com.cn就是一個域名,因為我們習慣了這種叫法。

    但是等等,你購買域名的時候商家會給你www這個前綴嗎?不會。因為sina.com.cn才是域名。域名是唯一的。

    那麼什麼是主機,主機就是這個域裡面的其中一台主機。我們可以給它命名為www,也可以命名為news。

    那麼 www.sina.com.cn就是一個主機名,news.sina.com.cn也是一個主機名。sina.com.cn域下就有兩台主機。

  2. 同一個IP的計算機是怎樣分布的

    同一個IP下的計算機有可能是相互獨立的計算機,這個很好理解,有點像我們學校的區域網。

    也有可能分布在同一台主機裡面不同的 虛擬主機 ,一台物理主機,裡面可以虛擬出多台邏輯主機,但是無論怎樣,它都是同一台物理主機。

  3. 計算機是怎樣與遠程計算機通信的

    計算機與計算機之間的通信實質上就是兩個進(線)程之間的通信,客戶端打開一個進(線)程,再打開一個埠,伺服器同樣有一個進(線)程和一個埠,再配合相關的協議,通過這一個出入口傳輸數據,計算機之間就可以通信啦!

    當我們用瀏覽器打開一個網頁,我們就相當於在本機上打開了一個瀏覽器進(線)程,並打開了一個埠,和伺服器進行通信。

    那麼要怎麼通過Internet準確找到我們想要進行通信的遠程計算機呢?這時候我們就要通過IP地址來準確定位,每台公網上的物理主機都有唯一的IP地址。就像我們需要根據學號來準確定位一個學生一樣。

  4. DNS伺服器的作用

    那麼等等,你可能會問,我們平時輸入網址時根本沒有指定伺服器的IP地址呀,怎麼就可以通信了呢,因為有DNS伺服器。

    DNS伺服器的作用就是用於域名解釋,我們平時輸入的網址例如:baidu.com,看得出來,並沒有任何IP地址的相關信息,但是有DNS伺服器幫我們找到了 .baidu.com域對應的IP地址,我們就不用煩心去記指定ip地址了。

  5. 怎麼通過同一域名找到對應的主機

    可能你又會問,既然同一域名通過DNS會被解釋為同一IP地址,那麼怎麼識別同一域內不同的主機呢?沒錯,通過主機名(host),這時主機名的作用就出來了。希望你看到這裡的時候還沒忘記主機名的概念。

  6. URL的作用

    什麼是URL,我不說概念本身,反正我們能通過它來定位到Internet上的某個資源,大家都很熟悉了,畢竟天天在地址欄輸入些奇奇怪怪的東西。

  7. 緩存的作用

    緩存,我也不說概念,大家肯定也不想聽概念。實際上緩存範圍也太廣了,從cpu到操作系統到瀏覽器都有緩存的概念。記著緩存就是就近取材,附近有的就肯定不會跑遠的地方去拿了。(除非你指定說不要就近取材)

  8. HTTP協議有什麼用

    超文本傳輸協議,暫時不用管協議本身,我們在瀏覽器輸入url的時候,如果要獲得某個資源,必須遵循http協議。

  9. HTTP協議是在什麼基礎上實現的

    HTTP其實只是眾多協議中的一部分,我們還有FTP,HTTPS,FILE、上面的DNS協議等等等等。而且這眾多協議也只是屬於TCP/IP協議簇上的「某一層」而已。關於TCP/IP協議簇,下面會說。

    現在先知道,HTTP是基於TCP/IP協議簇的就行了。TCP/IP協議簇是經濟基礎,HTTP是上層建築,經濟基礎決定上層建築!

  10. MVC模式是什麼

    有可能很多同學會疑惑MVC是什麼。MVC其實是軟體工程的概念,由於這篇文章只涉及web,那當然是針對web的mvc模式。第二部分會有詳細說明。

    我盡量寫得簡單點:

    模型(Model) - 後端程序員編寫後端代碼對數據進行管理、資料庫工程師進行數據管理和資料庫設計。

    控制器(Controller)- 對用戶發來的請求進行處理並返迴響應。請求是什麼,怎麼處理請求,響應是什麼,後面會說。

    視圖(View) - 頁面設計,當然啦,這個不僅僅是前端寫代碼的事了,還涉及到視覺及交互。

    我們輸入地址想看某個網頁的時候,就相當於向伺服器發送了請求。請求會交給controller進行處理,調取相關的數據,再展現給我們看。

  11. 請求是什麼?響應是什麼?

    請求是...是什麼?emmm...其實每次我們使用HTTP請求Internet上的資源的時候,瀏覽器都會發送一個請求到伺服器。我們稱之為請求報文。裡面包含必要的信息。

    你想想,你想讓伺服器干某件事,是不是必須讓伺服器知道你想要他幹什麼呢?下面直接動動手,馬上就能有個大概的理解。

    打開你的瀏覽器,按下F12打開調試窗口,轉到network標籤,輸入baidu.com,刷新,觀察調試窗口,從左邊找到baidu.com這個文件:

看看 它的右邊是不是有類似下圖這樣的東西,這個就是請求的頭部(request header),當然只是頭部而已,相應的還有請求體,現在先不用管它。

相應的就有響應頭部,自己去看看吧。有個印象即可。

二、具體實現過程

2.1 從請求產生到物理硬體

我上面提到過,HTTP協議是上層建築,它產生的請求必然是經過下層來傳輸的。希望你會好奇TCP/IP協議簇它是怎麼分層的。請看下圖:

以HTTP協議為例子,我來解釋一下報文傳輸的路徑:

1. 應用層的 HTTP協議生成請求報文,把請求報文傳給傳輸層.

2. 傳輸層的TCP協議為了讓報文傳輸方便,把報文進行分割成一個個片段,並在報

文上打上埠號並傳給網路層。(上面說過,計算機是通過埠通信的,必須

準確告知埠號)

3. 網路層的IP協議增加作為通信目的地的MAC地址後轉發給鏈路層,然後通過

層層的路由轉發,最終到達伺服器鏈路層。

4. 伺服器鏈路層依次往上遞交,到TCP層時數據被重新組裝。然後遞送給應用層的HTTP協

議進行解釋。

5. HTTP協議解釋完畢後返回HTTP響應,再經由TCP/IP協議回送給用戶。

這裡注意一下:

鏈路層到鏈路層並不是一步到位的,中間還需要經過眾多路由轉發,才能把報文傳送到伺服器鏈路層。我這樣畫是方便理解而已。途中傳送報文主要依靠的是IP協議。

2.2 域名解釋的過程

等等,我們好像忘了,還有域名解釋的過程。不然目標IP地址就不知道了。但並不是像上圖那樣一開始就向下層遞交數據。而是經過下面的步驟:

本機確實沒有緩存的時候,才會經過TCP/IP各層,然後去各伺服器獲取相應IP地址。

2.3 我的博客是怎麼部署的

這裡為什麼提我的博客部署呢?一是記錄一下自己的部署過程,二是方便理解下面的內容。

我使用了 python實現了一個小博客。使用 nginx + gunicorn + sqlite部署了博客。

那麼,這四者分別是什麼角色呢?

nginx: web伺服器。起到轉發請求、緩存數據的功能。

假如我有很多主機,那麼nginx就可以根據主機進行轉發請求,把請求發送到

不同的主機里。如果只有一台主機,它也可以把請求分為靜態資源請求和動態

資源請求,然後分別轉發。

gunicorn:web伺服器。負責接收nginx發來的HTTP請求,並把它轉換為Python能夠

識別的信息,且兼有進程管理功能。

python:能寫後端的代碼種類很多,這裡以Python為例。它接收了gunicorn傳來的請

求,然後讓代碼對請求進行處理,成功後返回一個響應並原路返回。

sqlite: 資料庫。用於與Python之間的數據交換。Python有驅動及介面調用sqlite。現在我們

不關心它是怎麼調用的。實際商用的話一般不用sqlite。

可能有同學會疑問,nginx 和 gunicorn的作用同樣是web伺服器,為什麼要放一起,其

實這裡的nginx更像一個路由的作用,負責分發請求,而不再是單純web伺服器了,可以叫它為反向代理伺服器。而gunicorn呢,有點像網關,把http翻譯一下交給Python處理。這裡把它叫做wsgi伺服器比較合適。

其實畫個圖就是這樣而已:圖片

其中:WSGI是一種應用程序介面規則,按照這種規則寫的Python代碼,gunicorn才能解讀。同樣地,經gunicorn解釋的http請求,要滿足WSGI規範才能被Python解讀。

2.4 後端處理

後端處理其實涉及的內容也是非常複雜的,特別是資料庫設計及優化,通常會有架構師及資料庫工程師把關。憑我目前水平也根本說不清楚,我利用我寫過的博客為例,盡量簡單明了把關鍵內容說明白。這裡只大概說一下MVC流程吧。

2.4.1 Model:

Model就相當於是數據,如果你在閱讀下文時覺得「Model」難以理解,可以先把它替換成「數據」兩個字。話不多說,看圖:

Model 設計

我解釋一下。這是我在剛學Python的時候打算搭建博客時,設計的Model。

這裡先說一個概念,現在我們都流行面向對象程序設計了,所以,數據會被結構化為一個個的對象,方便操縱它的屬性和行為。

看圖,有那麼幾個Model對象:Article(文章),Comment(評論),User(用戶),UserProfile(用戶檔案),Vote(點贊)。不要管裡面的其他框線,那是用來表示Model之間關係的。

這些對象就是我們在MVC中操縱的Model,那麼畫個圖我們就能操縱Model了?當然不是,請看:

Model

看綠色字,是不是看到了熟悉的單詞呢?Article,Comment,UserProfile。那麼我們把代碼寫出來就可以了嗎?當然不是,我們需要把這些Model相關的信息寫入資料庫。過程略去不說,反正你知道要寫入資料庫就行了。下面我們只關注Article

好了,假設我們已經把這些寫入資料庫了,那麼它們在資料庫里是怎樣表示的呢?先說一句:是以 表-條目 的形式的方式表示的。看圖:

資料庫

這是Article的表,裡面的條目就是一個個具體的Article!自己觀察一下表頭,跟剛才的代碼里的Article之間存在什麼關係呢?

好了,至此,我們的Model已經準備好了!就是說數據已經準備好了,讓客戶端的請求來得更猛烈些吧。

2.4.2 Controller

Controller接收到gunicorn發來的請求,根據請求提取Model里相關的數據,並告訴View:「喂,我這有個數據,把它展示到頁面上吧!怎麼展示你說了算。」話不多說,看圖:

Controller

代碼的意思大概是,我們的代碼接收了一個客戶端的請求,該請求定向到了我的博客主頁,於是我把資料庫裡面的Article都取了出來,並命名為articles.然後把articles傳給了一個叫blog/blog.html的文件。我們記著articles這個單詞往下看。

這裡注意一點:

我只是使用Python往資料庫寫入數據,但是資料庫的數據即Model本身是非常獨立的,被寫入的數據同樣可以被其他語言的controller調用,例如JAVA,Ruby等。

2.4.3 View

blog.html:「OK,收到,我把articles放到html裡面展示出來,加點CSS,變漂亮一點!」話不多說,看圖:

View

這是部分HTML代碼截圖。說明都在圖上了,不贅述了。

至此,我的Article Model 旅程算是結束了。

現在一個(漂亮的?)頁面就已經就緒了!就差把它弄到瀏覽器讓我們看見了!

其實還有一步,得把這個帶有數據的頁面作為HTTP響應返回給gunicorn!其實我在controller已經做了這一步了。這裡不用糾結細節。知道controller會接受請求,傳遞數據和返回請求就行了。

我賭五毛你會問,這就說完了?這些代碼就可以構建博客了嗎?我不信!我想看成品!代碼當然還有很多,但成品我放這裡了:我的博客。由於是小白一個,前後端一手抓,而且又不是使用博客客戶端搭建的,所以基本就是手擼的代碼(web框架還是用了的哈哈哈),難免功能簡單、頁面簡陋,大家見諒。好處就是以後我想搞什麼功能上去都可以。

好了,MVC的簡紹也就到此結束。

這時候...HTTP響應原路返回,一路就到了瀏覽器啦!

3.瀏覽器頁面處理

瀏覽器根據響應做出相應的動作,例如,響應的是一個html頁面,那麼就會對html頁面進行解釋,遇到需要再次請求的地方,例如一個css,一個JavaScript,則會再次向伺服器發起請求。

然後瀏覽器會對頁面進行文檔流的布局,分析元素的大小,內外邊距,是內聯元素還是塊級元素,是否佔用文檔流空間等,對HTML元素進行逐個布局(渲染樹)。遇到需要執行js的節點會執行相應js程序。

那麼如果響應不是一個html頁面呢?例如是一個重定向響應,那麼瀏覽器會根據相應報文的響應頭部信息確認重定向的位置。如果是一個404響應呢,那你就看到404頁面咯。

三. 總結:

話不多說,一圖流吧,主要是對HTTP報文的傳輸過程進行總結(當然是根據這篇文章的一圖總結了,其他不在此文內容的細節請忽略。)

有點大,點擊鏈接吧。圖片在這裡

四、最後:

本來是打算想寫TCP三次握手的,無奈了解的不夠多,知乎上也有關於TCP握手的深入淺出的答案,我就不獻醜了。

關於MVVM模式,已經逐漸替代了MVC模式,令頁面更加靈活,希望能深入接觸。


推薦閱讀:

ApiTestEngine 演化之路(1)搭建基礎框架
HTTP請求
如何實現200 from cache?
HTTP 在什麼情況下會請求超時?

TAG:HTTP | MVC |