網站結構分析(架構師教你來學大型網站架構的技術細節)

前端架構前面從宏觀的角度介紹瞭大型網站架構。從本篇開始,我們將著眼於細節,逐一展開介紹前面章節中提到的前端、後端、雲計算服務分層的技術架構。其中,前端部分是直接影響用戶體驗的,因此本篇先介紹前端部分的架構。需要註意的是,這裡的前端指的是B/S架構網站中的前端網頁,是靜態網頁。前端的工作原理在討論前端架構之前,我們先搭建一個前端Web服務器,再通過構造一個簡單的網頁來瞭解其工作原理。在瞭解前端網頁的工作原理之後,我們才能更好地理解前端架構需要註重的細節。WEB服務器搭建網頁想要被非本機的瀏覽器訪問,便需要搭建一個Web服務器。目前比較主流的Web服務器軟件有三個,即Apache、IIS和Nginx。Apache是目前使用最多的Web服務器軟件,它擁有極其穩定的性能,擴展模塊全面、多樣,且可以運行在Windows和Linux等多個平臺上;IIS是微軟提供的互聯網基本服務,它除瞭提供Web服務外,還提供FTP、NNTP和SMTP等服務,不過IIS隻能運行在Windows操作系統上;Nginx是輕量級的Web服務器軟件,它支持負載均衡和反向代理等功能,擴展模塊雖然沒有Apache全面,但比Apache占用的內存和資源少,在高並發處理上表現更好。Web服務器的選取需要根據具體情況而定。對於一般的大型網站而言,因為服務器操作系統一般以更為穩定的Linux為主,並且服務器需要應對大量的網頁請求(高並發),所以本書選用Nginx作為Web服務器軟件。Nginx的安裝以Windows系統和CentOS系統為例。選擇這兩個系統進行介紹是因為Windows一般是開發人員在開發時使用的操作系統,而CentOS一般是網站服務器操作系統。1.在Windows系統中安裝Nginx在Windows系統中安裝Nginx的具體操作步驟如下:(1)從Nginx官網(http://nginx.org/en/download.html)下載Nginx,一般選擇下載穩定版本。官網上的Nginx版本劃分如圖3.1所示,這裡我們下載Windows系統上的穩定版本。圖3.1 Nginx官網上的版本劃分(2)下載完Nginx壓縮包後,將其解壓到一個目錄下,其目錄結構如圖3.2所示。其中,html文件夾是默認存放網頁資源的地方,conf文件夾存放的是Nginx的相關配置文件,logs文件夾存放的是Nginx的運行日志。圖3.2 解壓後的Nginx目錄結構(3)修改Nginx配置,Nginx的配置文件是conf/nginx.conf。默認的配置文件如代碼3.1所示,其中,“…”是省略的意思,“#”後面是對屬性的註釋。如果是本地調試,保持默認配置即可。代碼3.1 默認的Nginx配置…server {listen 80; #端口,80為HTTP的默認端口server_name default_server; #服務名稱…location / {root html; #網頁資源文件夾,這裡的html指的是圖3.2中的html文件夾index index.html; #網站默認網頁}…}……(4)啟動服務,雙擊圖3.2中的nginx.exe文件即可,運行窗口會一閃而過。在不修改默認配置且正常啟動的情況下,在瀏覽器的地址中輸入http://localhost會打開Nginx的默認網頁,如圖3.3所示。這個默認網頁是圖3.2中html文件夾裡的index.html。圖3.3 Nginx的默認網頁如果不能正常啟動,可以查看圖3.2中logs文件夾裡的運行日志。不能啟動一般都是由於端口沖突造成的,此時可以修改步驟(3)中的listen配置項。如果在步驟(3)中修改瞭server_name和listen配置項,則需要在瀏覽器的地址欄中輸入server_name:listen。例如,將server_name設置為192.168.3.3,listen設置為8081,那麼在瀏覽器的地址欄中應該輸入http://192.168.3.3:8081。一般情況下,將server_name設置成default_server即可。另外,可以通過在任務管理器中結束所有nginx.exe任務來關閉Nginx服務,如圖3.4所示。圖3.4 關閉Nginx服務(5)設置防火墻。如果非本機的瀏覽器想要訪問網頁,則需要設置防火墻端口的權限。對於大型網站而言,服務器系統一般為Linux,Windows系統下的Nginx安裝一般隻是為瞭方便本地開發,非本機瀏覽器訪問的場景比較少,因此防火墻的設置不是必需的。如果開發時有非本機訪問的情況,可以暫時關閉Windows防火墻。2.在CentOS系統中安裝Nginx在Centos系統中安裝Nginx時,雖然也可以從官網上下載安裝,但是操作比較復雜。因此,這裡推薦使用yum安裝,這種安裝方式簡單方便且不易出錯,具體操作步驟如下:(1)添加Nginx源。在默認情況下,CentOS系統中不包含Nginx源,添加Nginx源的命令如代碼3.2所示,其中“\”為換行符。添加成功後,會在/etc/yum.repos.d目錄下多出一個nginx.repo文件。代碼3.2 添加Nginx源的命令sudo rpm -ivh \http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm(2)安裝Nginx的命令如代碼3.3所示。在CentOS系統中,Nginx默認安裝在/etc/nginx目錄下,配置文件是/etc/nginx/nginx.conf,運行日志的路徑是/var/log/nginx/,默認網頁資源存放在/usr/share/nginx/html/目錄下。代碼3.3 安裝Nginx的命令sudo yum -y install nginx(3)修改配置。Nginx的配置文件是/etc/nginx/nginx.conf,默認的配置文件如代碼3.4所示,其中,“…”是省略的意思,“#”後面是對屬性的註釋。如果是本地調試,保持默認配置即可。代碼3.4 CentOS系統中的Nginx配置server {listen 80; #端口,80為HTTP的默認端口server_name default_server; #服務名稱…location / {root /usr/share/nginx/html; #網頁資源文件目錄index index.html; #網站默認網頁}…}…(4)啟動服務。設置Nginx開機自動啟動、啟動服務和停止服務的命令如代碼3.5所示。其中,“#”表示註釋部分,輸入命令時不需要輸入,後文不再贅述。代碼3.5 Nginx的啟動命令sudo systemctl enable nginx #設置開機啟動sudo systemctl start nginx #啟動服務sudo systemctl stop nginx #停止服務(5)配置防火墻。一般經過步驟(4)的配置就能啟動Nginx瞭,但如果防火墻是開啟狀態的話,非本機瀏覽器是不能訪問網頁的,因此這裡需要配置防火墻。配置防火墻的命令如代碼3.6所示,命令需要按順序執行。代碼3.6 配置防火墻的命令sudo firewall-cmd –add-service=http –permanent #開啟防火墻的HTTP服務#打開端口,根據Nginx的端口配置,替換80即可sudo firewall-cmd –add-port=80/tcp –permanentsudo firewall-cmd –reload #重啟防火墻防火墻配置成功後,非本機瀏覽器訪問網頁的效果如圖3.5所示。圖3.5 非本機瀏覽器訪問網頁需要註意的是,如果有明確的Nginx版本要求的話,需要從官網上下載安裝。構造一個簡單的網頁安裝完Nginx後,有一個默認的網頁,如圖3.3或圖3.5所示。這個網頁隻有一個HTML文件,這與我們平常的網頁結構不一樣,這樣的網頁會造成我們對前端網頁工作原理的理解不夠全面。我們一般把一個網頁分成一個HTML文件、多個CSS樣式文件和多個JavaScript文件,因此在介紹前端工作原理之前,我們還需要構造一個簡單的網頁,該網頁將包含一個HTML文件、兩個CSS文件和兩個JavaScript文件。註意:本節構造的網頁隻是為瞭方便對3.1.3小節的講解,其中的編碼細節不作為現實編碼的參考。1.創建一個HTML文件創建一個abc.html文件,如代碼3.7所示。HTML文件主要用來設置網頁的屬性和定義頁面元素,這個頁面的元素主要包括標題、一行文字和按鈕。代碼3.7 abd.html文件的代碼<!DOCTYPE html> <!– 采用HTML5標準 –><html> <!– 文檔開始點 –><head> <!– 頭部元素開始點 –><meta charset="utf-8"> <!– 設置網頁屬性 –><title>簡單的例子</title> <!– 網頁標簽的名稱 –><link rel="stylesheet" href="css_1.css"> <!– 引用CSS文件 –><link rel="stylesheet" href="css_2.css"></head> <!– 頭部元素結束點 –><body> <!– 主體開始點 –><div class="title">簡單的翻譯例子</div> <!– 網頁元素:標題 –><span id="id_text">Hello World.</span> <!– 網頁元素:一行文字 –><button onclick="translates()">轉換</button> <!– 網頁元素:按鈕 –></body> <!– 主體結束點 –><script src="js_1.js"></script> <!– 引用JavaScript文件 –><script src="js_2.js"></script></html> <!– 文檔結束點 –>這裡需要明確一點,除瞭用iframe嵌入網頁的情況外,一個網頁隻有一個HTML文件。在HTML的規范中,除瞭<!DOCTYPE html>這樣的標準聲明外,其他的內容都應該包含在<html></html>中。而<html></html>裡面的內容主要包含頭部元素(<head></head>)和主體(<body></body>)兩個部分,頭部元素主要包含一些網頁屬性的設置,而主體才是網頁元素被定義的部分。HTML文件可以引用多個CSS樣式文件,引用CSS文件的位置一般在<head></head>中,這樣有利於網頁的加載,在後續工作原理的講解中會詳細說明。HTML文件可以引用多個JavaScript腳本文件,引用的位置一般在<body></body>之後,這樣有利於網頁的顯示,也能避免一些錯誤,在後續的工作原理中會詳細說明。註意:網頁元素(如按鈕等)寫在<body></body>外或<html></html>外,網頁仍會正常顯示,因為瀏覽器具有容錯機制,但這樣並非HTML規范的本意。2.創建兩個JavaScript文件下面創建兩個JavaScript文件,用來進行網頁的交互處理。第一個文件命名為js_1.js,如代碼3.8所示,其內容主要是定義兩個變量。代碼3.8 js_1.js文件的代碼var EnglishText = "Hello World.";var ChineseText = "你好,世界。";另一個文件命名為js_2.js,如代碼3.9所示,其內容是轉換網頁上的文字。在網頁上單擊按鈕後會調用此函數,代碼3.7中的“<buttononclick="translates()">轉換</button>”綁定瞭translates()函數。代碼3.9 js_2.js文件的代碼var translates = function() {var text = document.getElementById("id_text").innerText;if(text == EnglishText){document.getElementById("id_text").innerText = ChineseText;} else {document.getElementById("id_text").innerText = EnglishText;}}JavaScript本身沒有命名空間之類的限定,隻要在同一個HTML文件中被引用就可以互相調用。例如上例中,頁面引用瞭js_1.js和js_2.js兩個JavaScript文件,而js_2.js中的函數則可以直接使用js_1.js中定義的變量。註意:這裡的兩個JavaScript文件內容可以寫在一個JavaScript文件中,分為兩個JavaScript文件隻是為瞭模擬多個JavaScript文件的情況。3.創建兩個CSS文件下面創建兩個CSS樣式文件。CSS樣式文件的作用是給HTML文件中的網頁元素提供樣式和佈局設置,如提供字號大小、間距和顏色等設置。一個CSS文件命名為css_1.css,如代碼3.10所示,其內容是定義標題的樣式。代碼3.7中的“<div class="title">簡單的翻譯例子</div>”綁定瞭title這個樣式屬性。代碼3.10 css_1.css文件的代碼/* 定義標題的樣式 */.title{margin-bottom: 10px;font-size: 32px;}另一個CSS文件命名為css_2.css,如代碼3.11所示,其內容是定義文字的樣式。代碼3.7中的“<span id="id_text">Hello World.</span>”是通過id(id_text)綁定樣式屬性的。代碼3.11 css_2.css文件的代碼/* 定義文字的樣式 */#id_text{font-size: 20px;}註意:這裡的兩個樣式定義可以寫在一個CSS文件中,分成兩個CSS文件隻是為瞭模擬多個CSS文件的情況。4.發佈網頁為瞭後續對網頁地址說明的方便,下面在Nginx的網頁資源目錄下創建一個sample文件夾,把剛創建的abc.html、css_1.css、css_2.css、js_1.js和js_2.js文件放到sample文件夾內。以Windows系統中的Nginx為例,目錄結構如圖3.6所示。圖3.6 Nginx中的目錄結構在Nginx默認配置的情況下,在瀏覽器的地址欄中輸入http://localhost/sample/abc.html,顯示的頁面如圖3.7所示。圖3.7 頁面效果單擊“轉換”按鈕後將會轉換文字,如圖3.8所示。圖3.8 單擊按鈕後的網頁效果前端網頁的工作原理在成功構造一個簡單的網頁並運行後,接下來介紹前端網頁的工作原理。通過3.1.1小節和3.1.2小節的介紹我們知道,一個網頁要運行起來,至少需要兩步。第一步是搭建Web服務器,讓瀏覽器能請求並得到網頁資源文件;第二步是把網頁資源文件放到網頁服務器上。前端網頁的工作原理也分為兩部分介紹:一部分是瀏覽器加載網頁資源,介紹瀏覽器與Web服務器的關系;另一部分是瀏覽器運行網頁,介紹瀏覽器和網頁的關系。註意:本節默認以Chrome瀏覽器作為說明的對象。雖然不同瀏覽器運行網頁的工作原理會有所區別,但是整體流程是基本相同的。本節在原理講解上會省略很多細節,讀者隻需要大體瞭解即可。1.瀏覽器加載網頁資源一個網站是由很多個網頁組成的,每個網頁都有自己的地址。以3.1.2小節中的網頁為例,在瀏覽器的地址欄中輸入網址(http://localhost/sample/abc.html)並按Enter鍵後,相當於向服務器發送瞭一個請求。這個請求包含多個部分,如圖3.9所示,其中為瞭對網址有一個全面的解釋,此處補充瞭端口部分和參數部分。說明:類似於這樣的網址或某個資源的網絡地址,一般被稱為URL(Uniform Resource Locator,統一資源定位符),後面將以URL代替對網址或網絡地址的描述。圖3.9 網頁地址的結構協議(protocol):請求網頁資源的協議一般為HTTP或HTTPS。由於HTTPS具有更高的安全性,而且瀏覽器會對使用HTTP的網站提示“不安全”,所以現在一般使用HTTPS。如果使用HTTPS,則需要對Web服務器進行額外配置。不過,HTTPS隻是在HTTP的基礎上做瞭通信加密,這個加解密的過程是瀏覽器和Web服務器自動完成的,我們隻需要配置好Web服務器即可,這對網站開發本身沒有影響。主機名(hostname):這裡可以是域名或者服務器的公網IP。如果是域名的話,那麼在真正發送請求到網頁服務器之前,域名解析服務器(DNS)會自動把域名轉換成服務器的公網IP。域名解析服務器是公共資源(一般不能對其進行操作),在購買域名後,在購買域名的網站綁定域名和服務器的公網IP,即可自動同步信息到DNS。端口(port):一般使用默認端口。如果是默認端口,那麼可以省略端口部分。HTTP的默認端口是80,HTTPS的默認端口是443。協議+主機名+端口:有瞭這三部分,Web服務器就能收到用戶發送的請求。Web服務器收到請求後,會繼續對URL的後續部分進行解析。路徑(path):Web服務器根據路徑尋找資源,在如圖3.9所示的例子中,Web服務器會根據/sample/abc.html這個路徑找到abc.html網頁文件並把文件內容發送給瀏覽器。不過,資源不一定都是文件,也可能是後端接口。但無論請求的資源是什麼,Web服務器都會以字節流形式返回內容。參數(parameters):從“?”開始到最後都為參數部分,多個參數之間用“&”隔開。參數一般用在請求資源時,其處理不一定在服務器端進行,也可能由網頁的JavaScript腳本處理。說明:網址還可以添加信息片段部分,這部分一般是在整個網址的最末端以“#”開始,如http://localhost/sample/abc.html?id=123&type=1#home。信息片段部分隻會被網頁的JavaScript腳本處理,因此,如果隻更新這部分,那麼網頁是不會被瀏覽器刷新的。以上是對URL的介紹,下面我們回到瀏覽器加載網頁資源的過程。服務器在接收到請求後返回網頁文件,瀏覽器對網頁文件進行解析,當發現網頁文件中有其他需要下載的資源時(如代碼3.7中的<linkrel="stylesheet"href="css_2.css">),會向Web服務器請求新的文件。以3.1.2小節中的網頁為例,瀏覽器加載網頁資源的全過程如圖3.10所示。圖3.10 瀏覽器加載網頁資源的全過程註意:文件資源都以字節流的形式返回,瀏覽器每獲取一部分內容就會立即對其進行處理,而不會等全部獲取文件資源後再解析。資源請求的方式一般是異步請求,即不會等上一個請求的資源全部獲取後再開始請求下一個網頁資源。對於如圖3.10所示的請求過程,可以按F12鍵打開瀏覽器的開發工具查看具體的請求細節。以Chrome瀏覽器為例,其開發者工具如圖3.11所示。圖3.11 使用開發者工具查看資源請求的細節2.瀏覽器運行網頁瀏覽器顯示網頁的工作流程大概可以分成4部分,即構建DOM樹、構建呈現樹(render tree)、佈局處理和繪制頁面,如圖3.12所示。因為瀏覽器對網頁進行的是流式處理,所以此流程不是一次性完成的,而是每解析一部分網頁,都可能會執行一次流程。圖3.12 瀏覽器顯示網頁的流程可以將DOM樹理解為結構樹或內容樹。瀏覽器解析HTML文檔,並將各元素標簽逐個轉換成DOM節點,即把HTML文檔中的標簽轉換成一個結構樹。這個解析和構造過程是流式的,瀏覽器每獲取HTML的一部分,便會立刻對其進行解析。以3.1.2小節中的網頁為例,其DOM樹如圖3.13所示,其中省略瞭元素的屬性。圖3.13 DOM樹呈現樹是網頁顯示部分的數據結構。在構造DOM樹的同時,也會解析外部CSS文件及元素標簽中的樣式設置,瀏覽器會構造一個與CSS樣式對應的CSSOM樹。瀏覽器會利用CSSOM樹中的視覺屬性(如顏色和尺寸)和DOM樹對應的元素構造另一個結構——呈現樹。呈現樹和DOM樹相對應,可以簡單地理解為在DOM樹的節點上添加視覺屬性。但是呈現樹與DOM樹並非一一對應,呈現樹隻記錄在瀏覽器上可顯示的部分,一些非可視化的元素(如<head></head>)和一些被隱藏的元素是不會被記錄在呈現樹上的。仍以3.1.2小節中的網頁為例,其呈現樹如圖3.14所示。圖3.14 呈現樹呈現樹構造完畢之後,進入佈局處理階段。佈局處理階段主要是根據呈現樹和瀏覽器窗口的大小計算出每一個節點出現在屏幕上的確切坐標。最後進行繪制,即把網頁描畫出來。瀏覽器顯示網頁是漸進的過程,上文提到的流程並不是一次完成的。瀏覽器會盡快將內容顯示在屏幕上,而不是等到整個HTML文檔解析完畢才開始構建呈現樹和設置佈局。在不斷接收和處理網絡資源的同時,瀏覽器會不斷解析並顯示內容。在以上過程中並沒有提及JavaScript文件的作用。瀏覽器有專門的JavaScript解析器處理JavaScript文件。JavaScript解析器中會有一些預編譯的流程,不過這是內部行為,我們不必過於關心。JavaScript腳本可以響應網頁事件(如單擊和拖動等),調用瀏覽器的一些功能(如全屏等),以及與遠端服務器通信(請求數據)等。JavaScript腳本對於網頁顯示而言,其最大的作用是可以修改HTML內容(即可以改變DOM樹,一般來說,JavaScript腳本修改HTML內容的操作也被稱為DOM操作),HTML內容發生變化後,瀏覽器會自動進行網頁的重排和重繪,從而顯示新的網頁。例如3.1.2小節中的網頁,當單擊按鈕後,JavaScript腳本會自動改變網頁的文字內容。以上是前端網頁的工作原理。但是還有一個問題沒說清楚。在3.1.2小節中為什麼要把JavaScript文件的引用放在<body></body>的後面,而將CSS文件的引用放在<head></head>中呢?這是因為,瀏覽器雖然對HTML文件是流式處理的,但是JavaScript文件可能會修改HTML的內容,即可能會影響DOM樹的結構,從而影響呈現樹的構造及後續的流程,所以當瀏覽器處理到<script></script>標簽時,會停止對HTML文件的解析,先加載並處理完JavaScript文件後再繼續解析HTML文件。在一般情況下,JavaScript腳本隻在響應事件(如單擊)後才會操作HTML元素,因此把JavaScript的引用放在<body></body>的後面有利於DOM樹的構建,從而有利於網頁盡早顯示出來。再者,因為JavaScript腳本可能會操作DOM樹,如果放在開頭,則可能會導致由於被操作的元素還沒被構造出來而發生錯誤。而CSS文件由於不影響DOM樹的構造,因此當瀏覽器處理到<link></link>標簽時會繼續往下解析。因為CSS文件會影響呈現樹的構造,所以會暫停呈現樹的構造,直到CSS文件下載結束並解析完成。把CSS文件放在<head></head>中,可以讓瀏覽器盡早加載CSS文件,這樣有利於呈現樹的構造,從而有利於網頁盡早顯示。以3.1.2小節中的網頁為例,整個網頁解析的漸進過程如圖3.15所示。其中,黑色粗線為構造過程,這裡隻體現瞭DOM樹的構造和呈現樹的構造這兩部分,而省略瞭佈局處理和繪制這兩個瀏覽器的自發行為。圖3.15 網頁構造的全過程在不同的瀏覽器中,具體構造DOM樹和呈現樹的暫停點和開始點是有所區別的,不過大體上仍然如圖3.15所示。本文給大傢講解的內容是大型網站架構的技術細節:前端架構,前端的工作原理下篇文章給大傢講解的內容是大型網站架構的技術細節:前端架構,前端架構需要解決的問題覺得文章不錯的朋友可以轉發此文關註小編;感謝大傢的支持!

本文出自快速备案,转载时请注明出处及相应链接。

本文永久链接: https://kuaisubeian.cc/48449.html

kuaisubeian