Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲在线电影,91久久免费视频,亚洲一区二区三区福利在线

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          從輸入URL到頁面展示到底發生了什么

          開始寫這篇文章還是挺糾結的,因為網上搜索“從輸入url到頁面展示到底發生了什么”,你可以搜到一大堆的資料。而且面試這道題基本是必考題,二月份面試的時候,雖然知道這個過程發生了什么,不過當面試官一步步追問下去的,很多細節就不太清楚了。

          本文的目的是通過輸入url之后發生的事情來做知識的總結和擴展。所以文章可能會很雜。

          總的過程大概如下:

          1、輸入地址

          當我們開始在瀏覽器中輸入網址的時候,瀏覽器其實就已經在智能的匹配可能得 url 了,他會從歷史記錄,書簽等地方,找到已經輸入的字符串可能對應的 url,然后給出智能提示,讓你可以補全url地址。對于 google的chrome 的瀏覽器,他甚至會直接從緩存中把網頁展示出來,就是說,你還沒有按下 enter,頁面就出來了。

          2、瀏覽器查找域名的 IP 地址

           1、請求一旦發起,瀏覽器首先要做的事情就是解析這個域名,一般來說,瀏覽器會首先查看本地硬盤的 hosts 文件,看看其中有沒有和這個域名對應的規則,如果有的話就直接使用 hosts 文件里面的 ip 地址。

          2、如果在本地的 hosts 文件沒有能夠找到對應的 ip 地址,瀏覽器會發出一個 DNS請求到本地DNS服務器 。本地DNS服務器一般都是你的網絡接入服務器商提供,比如中國電信,中國移動。

          3、查詢你輸入的網址的DNS請求到達本地DNS服務器之后,本地DNS服務器會首先查詢它的緩存記錄,如果緩存中有此條記錄,就可以直接返回結果,此過程是遞歸的方式進行查詢。如果沒有,本地DNS服務器還要向DNS根服務器進行查詢。

          4、根DNS服務器沒有記錄具體的域名和IP地址的對應關系,而是告訴本地DNS服務器,你可以到域服務器上去繼續查詢,并給出域服務器的地址。這種過程是迭代的過程。

          5、本地DNS服務器繼續向域服務器發出請求,在這個例子中,請求的對象是.com域服務器。.com域服務器收到請求之后,也不會直接返回域名和IP地址的對應關系,而是告訴本地DNS服務器,你的域名的解析服務器的地址。

          6、最后,本地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查詢的兩種方式:遞歸查詢和迭代查詢

          1、遞歸解析

          當局部DNS服務器自己不能回答客戶機的DNS查詢時,它就需要向其他DNS服務器進行查詢。此時有兩種方式,如圖所示的是遞歸方式。局部DNS服務器自己負責向其他DNS服務器進行查詢,一般是先向該域名的根域服務器查詢,再由根域名服務器一級級向下查詢。最后得到的查詢結果返回給局部DNS服務器,再由局部DNS服務器返回給客戶端。


          2、迭代解析

          當局部DNS服務器自己不能回答客戶機的DNS查詢時,也可以通過迭代查詢的方式進行解析,如圖所示。局部DNS服務器不是自己向其他DNS服務器進行查詢,而是把能解析該域名的其他DNS服務器的IP地址返回給客戶端DNS程序,客戶端DNS程序再繼續向這些DNS服務器進行查詢,直到得到查詢結果為止。也就是說,迭代解析只是幫你找到相關的服務器而已,而不會幫你去查。比如說:baidu.com的服務器ip地址在192.168.4.5這里,你自己去查吧,本人比較忙,只能幫你到這里了。


          3)DNS域名稱空間的組織方式

          我們在前面有說到根DNS服務器,域DNS服務器,這些都是DNS域名稱空間的組織方式。按其功能命名空間中用來描述 DNS 域名稱的五個類別的介紹詳見下表中,以及與每個名稱類型的示例

          (盜圖)

          4)DNS負載均衡

           當一個網站有足夠多的用戶的時候,假如每次請求的資源都位于同一臺機器上面,那么這臺機器隨時可能會蹦掉。處理辦法就是用DNS負載均衡技術,它的原理是在DNS服務器中為同一個主機名配置多個IP地址,在應答DNS查詢時,DNS服務器對每個查詢將以DNS文件中主機記錄的IP地址按順序返回不同的解析結果,將客戶端的訪問引導到不同的機器上去,使得不同的客戶端訪問不同的服務器,從而達到負載均衡的目的?例如可以根據每臺機器的負載量,該機器離用戶地理位置的距離等等。

          3、瀏覽器向 web 服務器發送一個 HTTP 請求

          拿到域名對應的IP地址之后,瀏覽器會以一個隨機端口(1024<端口<65535)向服務器的WEB程序(常用的有httpd,nginx等)80端口發起TCP的連接請求。這個連接請求到達服務器端后(這中間通過各種路由設備,局域網內除外),進入到網卡,然后是進入到內核的TCP/IP協議棧(用于識別該連接請求,解封包,一層一層的剝開),還有可能要經過Netfilter防火墻(屬于內核的模塊)的過濾,最終到達WEB程序,最終建立了TCP/IP的連接。

          TCP連接如圖所示:


           建立了TCP連接之后,發起一個http請求。一個典型的 http request header 一般需要包括請求的方法,例如 GET 或者 POST 等,不常用的還有 PUT 和 DELETE 、HEAD、OPTION以及 TRACE 方法,一般的瀏覽器只能發起 GET 或者 POST 請求。

          客戶端向服務器發起http請求的時候,會有一些請求信息,請求信息包含三個部分:

          | 請求方法URI協議/版本

          | 請求頭(Request Header)

          | 請求正文:

          下面是一個完整的HTTP請求例子:

          GET/sample.jspHTTP/1.1Accept:image/gif.image/jpeg,*/*Accept-Language:zh-cn
          Connection:Keep-Alive
          Host:localhost
          User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
          Accept-Encoding:gzip,deflate
          username=jinqiao&password=1234
          

          注意:最后一個請求頭之后是一個空行,發送回車符和換行符,通知服務器以下不再有請求頭。

          (1)請求的第一行是“方法URL議/版本”:GET/sample.jsp HTTP/1.1

          (2)請求頭(Request Header)

          請求頭包含許多有關的客戶端環境和請求正文的有用信息。例如,請求頭可以聲明瀏覽器所用的語言,請求正文的長度等。

          Accept:image/gif.image/jpeg.*/*
          Accept-Language:zh-cn
          Connection:Keep-Alive
          Host:localhost
          User-Agent:Mozila/4.0(compatible:MSIE5.01:Windows NT5.0)
          Accept-Encoding:gzip,deflate.
          

          (3)請求正文

          請求頭和請求正文之間是一個空行,這個行非常重要,它表示請求頭已經結束,接下來的是請求正文。請求正文中可以包含客戶提交的查詢字符串信息:

          username=jinqiao&password=1234
          

          4、服務器的永久重定向響應

           服務器給瀏覽器響應一個301永久重定向響應,這樣瀏覽器就會訪問“http://www.google.com/” 而非“http://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)重定向原因:

          (1)網站調整(如改變網頁目錄結構);

          (2)網頁被移到一個新地址;

          (3)網頁擴展名改變(如應用需要把.php改成.Html或.shtml)。

          這種情況下,如果不做重定向,則用戶收藏夾或搜索引擎數據庫中舊地址只能讓訪問客戶得到一個404頁面錯誤信息,訪問流量白白喪失;再者某些注冊了多個域名的網站,也需要通過重定向讓訪問這些域名的用戶自動跳轉到主站點等。

          3)什么時候進行301或者302跳轉呢?

          當一個網站或者網頁24—48小時內臨時移動到一個新的位置,這時候就要進行302跳轉,而使用301跳轉的場景就是之前的網站因為某種原因需要移除掉,然后要到新的地址訪問,是永久性的。

          清晰明確而言:使用301跳轉的大概場景如下:

          1、域名到期不想續費(或者發現了更適合網站的域名),想換個域名。

          2、在搜索引擎的搜索結果中出現了不帶www的域名,而帶www的域名卻沒有收錄,這個時候可以用301重定向來告訴搜索引擎我們目標的域名是哪一個。

          3、空間服務器不穩定,換空間的時候。

          5、瀏覽器跟蹤重定向地址

          現在瀏覽器知道了 "http://www.google.com/"才是要訪問的正確地址,所以它會發送另一個http請求。這里沒有啥好說的

          6、服務器處理請求

          經過前面的重重步驟,我們終于將我們的http請求發送到了服務器這里,其實前面的重定向已經是到達服務器了,那么,服務器是如何處理我們的請求的呢?

          后端從在固定的端口接收到TCP報文開始,它會對TCP連接進行處理,對HTTP協議進行解析,并按照報文格式進一步封裝成HTTP Request對象,供上層使用。

          一些大一點的網站會將你的請求到反向代理服務器中,因為當網站訪問量非常大,網站越來越慢,一臺服務器已經不夠用了。于是將同一個應用部署在多臺服務器上,將大量用戶的請求分配給多臺機器處理。此時,客戶端不是直接通過HTTP協議訪問某網站應用服務器,而是先請求到Nginx,Nginx再請求應用服務器,然后將結果返回給客戶端,這里Nginx的作用是反向代理服務器。同時也帶來了一個好處,其中一臺服務器萬一掛了,只要還有其他服務器正常運行,就不會影響用戶使用。

          如圖所示:


          通過Nginx的反向代理,我們到達了web服務器,服務端腳本處理我們的請求,訪問我們的數據庫,獲取需要獲取的內容等等,當然,這個過程涉及很多后端腳本的復雜操作。由于對這一塊不熟,所以這一塊只能介紹這么多了。

          7、服務器返回一個 HTTP 響應

          經過前面的6個步驟,服務器收到了我們的請求,也處理我們的請求,到這一步,它會把它的處理結果返回,也就是返回一個HTPP響應。

          HTTP響應與HTTP請求相似,HTTP響應也由3個部分構成,分別是:

          l 狀態行

          l 響應頭(Response Header)

          l 響應正文

          HTTP/1.1 200 OK
          Date: Sat, 31 Dec 2005 23:59:59 GMT
          Content-Type: text/html;charset=ISO-8859-1
          Content-Length: 122<html>
          <head>
          <title>http</title>
          </head><body>
          <!-- body goes here -->
          </body>
          </html>
          

          狀態行:

          狀態行由協議版本、數字形式的狀態代碼、及相應的狀態描述,各元素之間以空格分隔。

          格式: HTTP-Version Status-Code Reason-Phrase CRLF

          例如: HTTP/1.1 200 OK

          -- 協議版本:是用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抓到的請求正文,紅色框中的:響應正文:


          8、瀏覽器顯示 HTML

          在瀏覽器沒有完整接受全部HTML文檔時,它就已經開始顯示這個頁面了,瀏覽器是如何把頁面呈現在屏幕上的呢?不同瀏覽器可能解析的過程不太一樣,這里我們只介紹webkit的渲染過程,下圖對應的就是WebKit渲染的過程,這個過程包括:

          解析html以構建dom樹 -> 構建render樹 -> 布局render樹 -> 繪制render樹


          瀏覽器在解析html文件時,會”自上而下“加載,并在加載過程中進行解析渲染。在解析過程中,如果遇到請求外部資源時,如圖片、外鏈的CSS、iconfont等,請求過程是異步的,并不會影響html文檔進行加載。

          解析過程中,瀏覽器首先會解析HTML文件構建DOM樹,然后解析CSS文件構建渲染樹,等到渲染樹構建完成后,瀏覽器開始布局渲染樹并將其繪制到屏幕上。這個過程比較復雜,涉及到兩個概念: reflow(回流)和repain(重繪)。

          DOM節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱為relow;當盒模型的位置,大小以及其他屬性,如顏色,字體,等確定下來之后,瀏覽器便開始繪制內容,這個過程稱為repain。

          頁面在首次加載時必然會經歷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)。具體的過程可以看我這篇文章:點擊這里

          9、瀏覽器發送請求獲取嵌入在 HTML 中的資源(如圖片、音頻、視頻、CSS、JS等等)

          其實這個步驟可以并列在步驟8中,在瀏覽器顯示HTML時,它會注意到需要獲取其他地址內容的標簽。這時,瀏覽器會發送一個獲取請求來重新獲得這些文件。比如我要獲取外圖片,CSS,JS文件等,類似于下面的鏈接:

          圖片:http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif

          CSS式樣表:http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css

          JavaScript 文件:http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js

          這些地址都要經歷一個和HTML讀取類似的過程。所以瀏覽器會在DNS中查找這些域名,發送請求,重定向等等...

          不像動態頁面,靜態文件會允許瀏覽器對其進行緩存。有的文件可能會不需要與服務器通訊,而從緩存中直接讀取,或者可以放到CDN中

          至此,從輸入url到頁面展示的過程終于整理完了。當然,文筆有限,有誤之處,歡迎指出,本文參考了很多的文章,不過很多文章的鏈接不記得了,所以只列出了下面三個參考鏈接。

          參考文獻:

          https://segmentfault.com/a/1190000006879700

          http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/

          http://zrj.me/archives/589

          、輸入地址

          當我們開始在瀏覽器中輸入網址的時候,瀏覽器其實就已經在智能的匹配可能得 url 了,他會從歷史記錄,書簽等地方,找到已經輸入的字符串可能對應的 url,然后給出智能提示,讓你可以補全url地址。對于 google的chrome 的瀏覽器,他甚至會直接從緩存中把網頁展示出來,就是說,你還沒有按下 enter,頁面就出來了。


          2、瀏覽器查找域名的 IP 地址  

          1、請求一旦發起,瀏覽器首先要做的事情就是解析這個域名,一般來說,瀏覽器會首先查看本地硬盤的 hosts 文件,看看其中有沒有和這個域名對應的規則,如果有的話就直接使用 hosts 文件里面的 ip 地址。

          2、如果在本地的 hosts 文件沒有能夠找到對應的 ip 地址,瀏覽器會發出一個 DNS請求到本地DNS服務器 。本地DNS服務器一般都是你的網絡接入服務器商提供,比如中國電信,中國移動。

          3、查詢你輸入的網址的DNS請求到達本地DNS服務器之后,本地DNS服務器會首先查詢它的緩存記錄,如果緩存中有此條記錄,就可以直接返回結果,此過程是遞歸的方式進行查詢。如果沒有,本地DNS服務器還要向DNS根服務器進行查詢。

          4、根DNS服務器沒有記錄具體的域名和IP地址的對應關系,而是告訴本地DNS服務器,你可以到域服務器上去繼續查詢,并給出域服務器的地址。這種過程是迭代的過程。

          5、本地DNS服務器繼續向域服務器發出請求,在這個例子中,請求的對象是.com域服務器。.com域服務器收到請求之后,也不會直接返回域名和IP地址的對應關系,而是告訴本地DNS服務器,你的域名的解析服務器的地址。

          6、最后,本地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查詢的兩種方式:遞歸查詢和迭代查詢

          1、遞歸解析

          當局部DNS服務器自己不能回答客戶機的DNS查詢時,它就需要向其他DNS服務器進行查詢。此時有兩種方式,如圖所示的是遞歸方式。局部DNS服務器自己負責向其他DNS服務器進行查詢,一般是先向該域名的根域服務器查詢,再由根域名服務器一級級向下查詢。最后得到的查詢結果返回給局部DNS服務器,再由局部DNS服務器返回給客戶端。

          2、迭代解析

          當局部DNS服務器自己不能回答客戶機的DNS查詢時,也可以通過迭代查詢的方式進行解析,如圖所示。局部DNS服務器不是自己向其他DNS服務器進行查詢,而是把能解析該域名的其他DNS服務器的IP地址返回給客戶端DNS程序,客戶端DNS程序再繼續向這些DNS服務器進行查詢,直到得到查詢結果為止。也就是說,迭代解析只是幫你找到相關的服務器而已,而不會幫你去查。比如說:baidu.com的服務器ip地址在192.168.4.5這里,你自己去查吧,本人比較忙,只能幫你到這里了。

          3.DNS域名稱空間的組織方式

          我們在前面有說到根DNS服務器,域DNS服務器,這些都是DNS域名稱空間的組織方式。按其功能命名空間中用來描述 DNS 域名稱的五個類別的介紹詳見下表中,以及與每個名稱類型的示例

          4.DNS負載均衡

          當一個網站有足夠多的用戶的時候,假如每次請求的資源都位于同一臺機器上面,那么這臺機器隨時可能會蹦掉。處理辦法就是用DNS負載均衡技術,它的原理是在DNS服務器中為同一個主機名配置多個IP地址,在應答DNS查詢時,DNS服務器對每個查詢將以DNS文件中主機記錄的IP地址按順序返回不同的解析結果,將客戶端的訪問引導到不同的機器上去,使得不同的客戶端訪問不同的服務器,從而達到負載均衡的目的?例如可以根據每臺機器的負載量,該機器離用戶地理位置的距離等等。


          3、瀏覽器向 web 服務器發送一個 HTTP 請求

          拿到域名對應的IP地址之后,瀏覽器會以一個隨機端口(1024<端口<65535)向服務器的WEB程序(常用的有httpd,nginx等)80端口發起TCP的連接請求。這個連接請求到達服務器端后(這中間通過各種路由設備,局域網內除外),進入到網卡,然后是進入到內核的TCP/IP協議棧(用于識別該連接請求,解封包,一層一層的剝開),還有可能要經過Netfilter防火墻(屬于內核的模塊)的過濾,最終到達WEB程序,最終建立了TCP/IP的連接。
            
          TCP連接如圖所示:   

          建立了TCP連接之后,發起一個http請求。一個典型的 http request header 一般需要包括請求的方法,例如 GET 或者 POST 等,不常用的還有 PUT 和 DELETE 、HEAD、OPTION以及 TRACE 方法,一般的瀏覽器只能發起 GET 或者 POST 請求。
            
          客戶端向服務器發起http請求的時候,會有一些請求信息,請求信息包含三個部分:

          請求方法URI協議/版本

          請求頭(Request Header)

          請求正文

          下面是一個完整的HTTP請求例子:

          GET/sample.jspHTTP/1.1
          Accept:image/gif.image/jpeg,*/*
          Accept-Language:zh-cn
          Connection:Keep-Alive
          Host:localhost
          User-Agent:Mozila/4.0(compatible;MSIE5.01;Window?NT5.0)
          Accept-Encoding:gzip,deflate
          
          username=jinqiao&password=1234
          

          注意:最后一個請求頭之后是一個空行,發送回車符和換行符,通知服務器以下不再有請求頭。

          1.請求的第一行是“方法URL議/版本”:GET/sample.jsp HTTP/1.1
          2.請求頭(Request Header)

          請求頭包含許多有關的客戶端環境和請求正文的有用信息。例如,請求頭可以聲明瀏覽器所用的語言,請求正文的長度等。

          Accept:image/gif.image/jpeg.*/*
          Accept-Language:zh-cn
          Connection:Keep-Alive
          Host:localhost
          User-Agent:Mozila/4.0(compatible:MSIE5.01:Windows?NT5.0)
          Accept-Encoding:gzip,deflate.
          

          3.請求正文
          請求頭和請求正文之間是一個空行,這個行非常重要,它表示請求頭已經結束,接下來的是請求正文。請求正文中可以包含客戶提交的查詢字符串信息:

          username=jinqiao&password=1234
          

          — 知識擴展—

          1.TCP三次握手

          第一次握手:客戶端A將標志位SYN置為1,隨機產生一個值為seq=J(J的取值范圍為=1234567)的數據包到服務器,客戶端A進入SYN_SENT狀態,等待服務端B確認;

          第二次握手:服務端B收到數據包后由標志位SYN=1知道客戶端A請求建立連接,服務端B將標志位SYN和ACK都置為1,ack=J+1,隨機產生一個值seq=K,并將該數據包發送給客戶端A以確認連接請求,服務端B進入SYN_RCVD狀態。

          第三次握手:客戶端A收到確認后,檢查ack是否為J+1,ACK是否為1,如果正確則將標志位ACK置為1,ack=K+1,并將該數據包發送給服務端B,服務端B檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,客戶端A和服務端B進入ESTABLISHED狀態,完成三次握手,隨后客戶端A與服務端B之間可以開始傳輸數據了。

          如圖所示:

          2.為什需要三次握手?

          《計算機網絡》第四版中講“三次握手”的目的是“為了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤”

          書中的例子是這樣的,“已失效的連接請求報文段”的產生在這樣一種情況下:client發出的第一個連接請求報文段并沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以后的某個時間才到達server。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段后,就誤認為是client再次發出的一個新的連接請求。于是就向client發出確認報文段,同意建立連接。

          假設不采用“三次握手”,那么只要server發出確認,新的連接就建立了。由于現在client并沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據。但server卻以為新的運輸連接已經建立,并一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。采用“三次握手”的辦法可以防止上述現象發生。例如剛才那種情況,client不會向server的確認發出確認。server由于收不到確認,就知道client并沒有要求建立連接。”。主要目的防止server端一直等待,浪費資源。

          3.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狀態,完成四次揮手。

          4.為什么建立連接是三次握手,而關閉連接卻是四次揮手呢?

          這是因為服務端在LISTEN狀態下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發送給客戶端。而關閉連接時,當收到對方的FIN報文時,僅僅表示對方不再發送數據了但是還能接收數據,己方也未必全部數據都發送給對方了,所以己方可以立即close,也可以發送一些數據給對方后,再發送FIN報文給對方來表示同意現在關閉連接,因此,己方ACK和FIN一般都會分開發送。


          4、服務器的永久重定向響應

          服務器給瀏覽器響應一個301永久重定向響應,這樣瀏覽器就會訪問http://www.google.com/而非http://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重定向來告訴搜索引擎我們目標的域名是哪一個。

          空間服務器不穩定,換空間的時候。

          5、瀏覽器跟蹤重定向地址

          現在瀏覽器知道了 http://www.google.com/ 才是要訪問的正確地址,所以它會發送另一個http請求。


          6、服務器處理請求

          經過前面的重重步驟,我們終于將我們的http請求發送到了服務器這里,其實前面的重定向已經是到達服務器了,那么,服務器是如何處理我們的請求的呢?

          后端從在固定的端口接收到TCP報文開始,它會對TCP連接進行處理,對HTTP協議進行解析,并按照報文格式進一步封裝成HTTP Request對象,供上層使用。

          一些大一點的網站會將你的請求到反向代理服務器中,因為當網站訪問量非常大,網站越來越慢,一臺服務器已經不夠用了。于是將同一個應用部署在多臺服務器上,將大量用戶的請求分配給多臺機器處理。

          此時,客戶端不是直接通過HTTP協議訪問某網站應用服務器,而是先請求到Nginx,Nginx再請求應用服務器,然后將結果返回給客戶端,這里Nginx的作用是反向代理服務器。同時也帶來了一個好處,其中一臺服務器萬一掛了,只要還有其他服務器正常運行,就不會影響用戶使用。

          如圖所示:

          通過Nginx的反向代理,我們到達了web服務器,服務端腳本處理我們的請求,訪問我們的數據庫,獲取需要獲取的內容等等,當然,這個過程涉及很多后端腳本的復雜操作。由于對這一塊不熟,所以這一塊只能介紹這么多了。

          —-擴展閱讀—-

          1.什么是反向代理?

          客戶端本來可以直接通過HTTP協議訪問某網站應用服務器,網站管理員可以在中間加上一個Nginx,客戶端請求Nginx,Nginx請求應用服務器,然后將結果返回給客戶端,此時Nginx就是反向代理服務器。


          7、服務器返回一個 HTTP 響應 

          經過前面的6個步驟,服務器收到了我們的請求,也處理我們的請求,到這一步,它會把它的處理結果返回,也就是返回一個HTPP響應。

          HTTP響應與HTTP請求相似,HTTP響應也由3個部分構成,分別是:

          狀態行

          響應頭(Response Header)

          響應正文


          HTTP/1.1?200?OK
          Date:?Sat,?31?Dec?2005?23:59:59?GMT
          Content-Type:?text/html;charset=ISO-8859-1
          Content-Length:?122
          
          <html>
          <head>
          <title>http</title>
          </head>
          <body>
          <!--?body?goes?here?-->
          </body>
          </html>
          

          狀態行:

          狀態行由協議版本、數字形式的狀態代碼、及相應的狀態描述,各元素之間以空格分隔。

          格式: HTTP-Version Status-Code Reason-Phrase CRLF
          例如: HTTP/1.1 200 OK

          協議版本:是用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抓到的請求正文,紅色框中的:響應正文:


          8、瀏覽器顯示 HTML

          在瀏覽器沒有完整接受全部HTML文檔時,它就已經開始顯示這個頁面了,瀏覽器是如何把頁面呈現在屏幕上的呢?不同瀏覽器可能解析的過程不太一樣,這里我們只介紹webkit的渲染過程,下圖對應的就是WebKit渲染的過程,這個過程包括:

          解析html以構建dom樹 -> 構建render樹 -> 布局render樹 -> 繪制render樹

          瀏覽器在解析html文件時,會”自上而下“加載,并在加載過程中進行解析渲染。在解析過程中,如果遇到請求外部資源時,如圖片、外鏈的CSS、iconfont等,請求過程是異步的,并不會影響html文檔進行加載。

          解析過程中,瀏覽器首先會解析HTML文件構建DOM樹,然后解析CSS文件構建渲染樹,等到渲染樹構建完成后,瀏覽器開始布局渲染樹并將其繪制到屏幕上。這個過程比較復雜,涉及到兩個概念: reflow(回流)和repain(重繪)。

          DOM節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱為relow;當盒模型的位置,大小以及其他屬性,如顏色,字體,等確定下來之后,瀏覽器便開始繪制內容,這個過程稱為repain。

          頁面在首次加載時必然會經歷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)。具體的過程可以看這篇文章:

          http://www.cnblogs.com/xianyulaodi/p/6414805.html


          9、瀏覽器發送請求獲取嵌入在 HTML 中的資源(如圖片、音頻、視頻、CSS、JS等等)

          其實這個步驟可以并列在步驟8中,在瀏覽器顯示HTML時,它會注意到需要獲取其他地址內容的標簽。這時,瀏覽器會發送一個獲取請求來重新獲得這些文件。比如我要獲取外圖片,CSS,JS文件等,類似于下面的鏈接:

          圖片:http://static.ak.fbcdn.net/rsrc.php/z12E0/hash/8q2anwu7.gif
          CSS式樣表:http://static.ak.fbcdn.net/rsrc.php/z448Z/hash/2plh8s4n.css
          JavaScript 文件:http://static.ak.fbcdn.net/rsrc.php/zEMOA/hash/c8yzb6ub.js

          這些地址都要經歷一個和HTML讀取類似的過程。所以瀏覽器會在DNS中查找這些域名,發送請求,重定向等等…

          不像動態頁面,靜態文件會允許瀏覽器對其進行緩存。有的文件可能會不需要與服務器通訊,而從緩存中直接讀取,或者可以放到CDN中

          1. RLRewrite介紹
            官網地址:http://www.tuckey.org/urlrewrite/
            UrlRewrite就是我們通常說的地址重寫,用戶得到的全部是經過處理后的URL地址,類似于Apache的mod_rewrite。將我們的動態網頁地址轉化為靜態的地址,如html、shtml,還可以隱藏網頁的真正路徑,比如:有時候需要將xxx.com/news/type1/001.jsp轉化成顯示路徑為:xxx.com/news_type1_001.html
            優點如下:
            - 提高安全性,屏蔽內部的url結構。
            - 美化URL
            - 更有利于搜索引擎的收入,通過對URL的一些優化,可以使搜索引擎更好識別與收錄網站的信息。
          2. URLRewrite應用環境搭建
            maven配置依賴jar包
          <!-- urlrewritefilter -->
          <dependency>
          	<groupId>org.tuckey</groupId>
          	<artifactId>urlrewritefilter</artifactId>
          	<version>4.0.3</version>
          </dependency>

          在WEB-INF/web.xml中增加配置

          <!-- 加到任何servlet映射的頂部,不然可能有些路徑不能被過濾到 -->
          <filter>
          	<filter-name>UrlRewriteFilter</filter-name>
          	<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
           
          	<!-- 設備文件重加載間隔 (0默示隨時加載, -1默示不重加載, 默認-1) -->
          	<init-param>
          		<param-name>confReloadCheckInterval</param-name>
          		<param-value>60</param-value>
          	</init-param>
           
          	<!-- 自定義配置文件的路徑,是相對context的路徑,(默認位置 /WEB-INF/urlrewrite.xml) -->
          	<init-param>
          		<param-name>confPath</param-name>
          		<param-value>/WEB-INF/urlrewrite.xml</param-value>
          	</init-param>
           
          	<!-- 設置日志級別(將被記錄到日志中) 
          		可以為: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons, slf4j, 
          		比如 sysout:DEBUG(設置到控制臺調試輸出級別) (默認級別 WARN) 
          	-->
          	<init-param>
          		<param-name>logLevel</param-name>
          		<param-value>DEBUG</param-value>
          	</init-param>
          </filter>
           
          <filter-mapping>
          	<filter-name>UrlRewriteFilter</filter-name>
          	<url-pattern>/*</url-pattern>
          	<dispatcher>REQUEST</dispatcher>
          	<dispatcher>FORWARD</dispatcher>
          </filter-mapping>

          如果覺得/*這樣的通配,并不符合我的預期,我只想對部分路徑進行URL的重寫,/*可能會造成我想象不到的或者是微不足道的性能浪費,我把它改成了我需要的,如下:

          <filter-mapping>
          	<filter-name>UrlRewriteFilter</filter-name>
          	<url-pattern>/member/*</url-pattern>
          </filter-mapping>
          <filter-mapping>
          	<filter-name>UrlRewriteFilter</filter-name>
          	<url-pattern>/article/*</url-pattern>
          </filter-mapping>

          增加并配置WEB-INF/urlrewrite.xml

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE urlrewrite
              PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
              "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
           
          <urlrewrite>
          	<rule>
          		<note>單用戶請求的路徑為/test/status/時,將被redirected(重定向)到/index.jsp</note>
          		<from>/test/status/</from>
          		<to type="redirect">%{context-path}/index01.jsp</to>
          	</rule>
          	<!-- redirect one url -->
          	<rule>
          		<from>/some/old/page.html</from>
          		<to type="redirect">/very/new/page.html</to>
          	</rule>
          	<!-- redirect a directory -->
          	<rule>
          		<from>/some/olddir/(.*)</from>
          		<to type="redirect">/very/newdir/$1</to>
          	</rule>
          	<!-- clean a url,例如:/products/1234 將轉換成 /products/index.jsp?product_id=1234 -->
          	<rule>
          		<from>/products/([0-9+])</from>
          		<to>/products/index.jsp?product_id=$1</to>
          	</rule>
          	<!-- 檢測瀏覽器 -->
          	<rule>
          		<condition name="user-agent">Mozilla/[1-4]</condition>
          		<from>/some/page.html</from>
          		<to>/some/page-for-old-browsers.html</to>
          	</rule>
          	<!-- 檢測瀏覽器,并設置請求參數
          		所有的請求都將被檢測,如果滿足條件,將調用request.setAttribute("browser", "moz")
          	 -->
          	<rule>
          		<condition name="user-agent">Mozilla/[1-4]</condition>
          		<set type="request" name="browser">moz</set>
          	</rule>
          	<!-- 配置JSTL使用, 單使用<c:url..>時,會自動轉換 -->
          	<outbound-rule>
          		<note>
          			The outbound-rule specifies that when response.encodeURL is
          			called (if you are using JSTL c:url) the url /rewrite-status 
          			will be rewritten to /test/status/. 
          			The above rule and this outbound-rule means that end users should never see 
          			the url /rewrite-status only /test/status/both in thier location bar and in 
          			hyperlinks in yourpages.
          		</note>
          		<from>/rewrite-status/(.*)</from>
          		<to>/index.jsp?param=$1</to>
          	</outbound-rule>
          </urlrewrite>
          

          3. URLRewrite使用示例

          • 示例01
          <rule>
          	<from>/page/(.*).html</from>
          	<to>/index.jsp?currentPage=$1</to>
          </rule>

          在index.jsp頁面中可以使用并接收參數

          <body>
            <%
              String current = request.getParameter("currentPage");
            %>
            <%=current %>
          </body>
          • 示例02
          <rule>
          	<name>World Rule</name>
          	<from>^/user/([a-z]+)/([0-9]+)$</from>
          	<to>/index.jsp?nickname=$1&age=$2</to>
          </rule>

          所以,當我們在url中輸入"http://localhost/urlrewrite/user/dennisit/23"時,實際執行的就是"http://localhost/urlrewrite/index.jsp?nickname=dennisit&age=23"

          • 示例03
          <rule>
          	<name>World Rule</name>
          	<from>^/user/([a-z]+)/([0-9]+)$</from>
          	<to>/index.jsp?nickname=$1&age=$2</to>
          </rule>

          這樣我們訪問"http://localhost/urlrewrite/page/test"時,則跳轉到"http://localhost/urlrewrite/page/test.action"

          • 示例04
          <rule>
              <from>^/([a-z]+)/([a-z]+)/([a-z]+)$</from>
              <to>/$1.do?method=$2&uuid=$3</to>
          </rule>

          在地址欄中顯示輸入的url是:http://localhost/urlrewrite/process/show/index

          其實際執行路徑是:http://localhost/urlrewrite/process.do?method=show&uuid=index


          主站蜘蛛池模板: 国产激情无码一区二区app| 无码精品不卡一区二区三区| 中文字幕一区视频| 波多野结衣一区在线观看| 久久精品道一区二区三区| 冲田杏梨高清无一区二区| 2022年亚洲午夜一区二区福利 | 91一区二区三区四区五区| 亚洲片国产一区一级在线观看| 精品人妻无码一区二区三区蜜桃一| 精品国产日产一区二区三区| 国产A∨国片精品一区二区| 日本精品夜色视频一区二区| 日韩在线视频一区| 日韩美一区二区三区| 国产精品一区二区三区高清在线| 亚洲变态另类一区二区三区 | 精品女同一区二区三区在线| 三上悠亚一区二区观看| 人妻无码一区二区视频| 日本精品少妇一区二区三区| 视频一区二区三区免费观看| 无码日韩精品一区二区人妻| 国产一区二区三区免费视频| 免费人妻精品一区二区三区| 一区二区三区久久精品| 国产精品一区12p| 日本视频一区在线观看免费| 少妇无码一区二区二三区| 久久精品国产一区二区三 | 国产一区二区在线| 欧洲亚洲综合一区二区三区| 精品一区二区三区3d动漫| 精品久久国产一区二区三区香蕉| 久久国产三级无码一区二区| 国99精品无码一区二区三区| 久久er99热精品一区二区| 中文字幕精品一区二区| 在线观看日韩一区| 中文字幕一区二区日产乱码| 一区二区三区四区免费视频|