今天面試,面試官問了我一個前端路由與後端路由的問題,我只回答到了一點,面試官叫我再去了解一下javascript
其實我以前在上線本身的博客遇到過下面這些問題php
/
的頁面呢理解Web路由這篇文章講得特別好了。html
在Web開發過程當中,常常會遇到『路由』的概念。那麼,到底什麼是路由?簡單來講,路由就是URL到函數的映射。前端
訪問的URL會映射到相應的函數裏(這個函數是廣義的,能夠是前端的函數也能夠是後端的函數),而後由相應的函數來決定返回給這個URL什麼東西。路由就是在作一個匹配的工做。vue
在web開發早期的「刀耕火種」年代裏,一直是後端路由佔據主導地位。無論是php,仍是jsp、asp,用戶能經過URL訪問到的頁面,大可能是經過後端路由匹配以後再返回給瀏覽器的。經典面試題,「你從瀏覽器地址欄裏輸入www.baidu.com
到你看到網頁這個過程當中經歷了什麼」其實講的也是這個道理。java
在web後端,無論是什麼語言的後端框架,都會有一個專門開闢出來的路由模塊或者路由區域,用來匹配用戶給出的URL地址,以及一些表單提交、ajax請求的地址。一般遇到沒法匹配的路由,後端將會返回一個404
狀態碼。這也是咱們常說的404 NOT FOUND
的由來。node
若是你關注RESTful API,那麼將會很熟悉下面四種發起請求的類型:GET
,POST
,PUT
,DELETE
。react
它們分別對應四種基本操做:GET用來獲取資源,POST用來新建資源(也能夠用於更新資源),PUT用來更新資源,DELETE用來刪除資源。——來自阮一峯《理解RESTful架構》webpack
雖然上面說的是RESTful API,可是實際上咱們在地址欄輸入一個URL,並回車的時候,是以GET
請求發出去的。這也體現了,URL地址和請求的method也應該是一一對應。下面給出一個例子:git
1 |
router.post('/user/:id', addUser) |
假如個人後端路由配置裏只有這一句路由。那麼我經過瀏覽器裏訪問:http://xxx.com/user/123
的話是沒法訪問到的,也會返回一個404。由於後端只配了一個post
方法的路由。若是要接受這個請求,那麼必須有以下的路由:
1 |
router.get('/user/:id', getUser) // 配置get路由 |
前面說了,「刀耕火種」的年代裏,網頁一般是經過後端路由直出給客戶端瀏覽器的。也就是網頁的html通常是在後端服務器裏經過模板引擎渲染好再交給前端的。至於一些其餘的效果,是經過預先寫在頁面裏的jQuery、Bootstrap等常見的前端框架去負責的。
若是你說有些網站已是經過ajax去實現的頁面,好比gmail,好比qq郵箱。那麼你要注意到哪怕是這些頁面,它們頁面的「龍骨」也並不是是所有經過ajax去實現的,依然仍是後端直出——這也就是咱們如今又老生常談的服務端渲染。
服務端渲染的好處有不少,好比對於SEO友好,一些對安全性要求高的頁面採用服務端渲染是更保險的。而在當時尚未node.js的年代,爲了良好地構建前端頁面,都是經過服務端語言對應的模板引擎來實現動態網頁、頁面結構的組織、組件的複用。好比Laravel的blade,用在Django上的jinja2,用在Struts的jsp等等。實際上到現在,一門後端語言想要能實現本身的web功能,都須要有本身對應的模板引擎。
node.js誕生以後,前端擁有本身的後端渲染的模板引擎也成爲了現實。常見的好比pug、ejs、nunjucks等。這些模板引擎搭配Express、Koa等後端框架也在一開始風靡一時。
不過在這個過程當中,隨着web應用的開發愈來愈複雜,單純服務端渲染的問題開始慢慢的暴露出來了——耦合性太強了,jQuery時代的頁面很差維護,頁面切換白屏嚴重等等。耦合性問題雖然能經過良好的代碼結構、規範來解決,不過jQuery時代的頁面很差維護這是有目共睹的,全局變量滿天飛,代碼入侵性過高。後續的維護一般是在給前面的代碼打補丁。而頁面切換的白屏問題雖然能夠經過ajax、或者iframe等來解決,可是在實現上就麻煩了——進一步增長了可維護的難度。
因而,咱們開始進入了前端路由的時代。
前端路由——顧名思義,頁面跳轉的URL規則匹配由前端來控制。而前端路由主要是有兩種顯示方式:
#
號很差看#
號,好看。缺點是既須要瀏覽器支持也須要後端服務器支持前端路由應用最普遍的例子就是當今的SPA的web項目。無論是Vue、React仍是Angular的頁面工程,都離不開相應配套的router工具。前端路由帶來的最明顯的好處就是,地址欄URL的跳轉不會白屏了——這也得益於前端渲染帶來的好處。
講前端路由就不能不說前端渲染。我以Vue項目爲例。若是你是用官方的vue-cli
搭配webpack模板構建的項目,你有沒有想過你的瀏覽器拿到的html是什麼樣的?是你頁面長的那樣有button
有form
的樣子麼?我想不是的。在生產模式下,你看看構建出來的index.html
長什麼樣:
1 |
|
一般長上面這個樣子。能夠看到,這個其實就是你的瀏覽器從服務端拿到的html。這裏面空蕩蕩的只有一個<div id="app"></div>
這個入口的div以及下面配套的一系列js文件。因此你看到的頁面實際上是經過那些js渲染出來的。這也是咱們常說的前端渲染。
前端渲染把渲染的任務交給了瀏覽器,經過客戶端的算力來解決頁面的構建,這個很大程度上緩解了服務端的壓力。並且配合前端路由,無縫的頁面切換體驗天然是對用戶友好的。不過帶來的壞處就是對SEO不友好,畢竟搜索引擎的爬蟲只能爬到上面那樣的html,對瀏覽器的版本也會有相應的要求。
須要明確的是,只要在瀏覽器地址欄輸入URL再回車,是必定會去後端服務器請求一次的。而若是是在頁面裏經過點擊按鈕等操做,利用router庫的api來進行的URL更新是不會去後端服務器請求的。
hash模式利用的是瀏覽器不會對#
號後面的路徑對服務端發起路由請求。也即在瀏覽器裏輸入以下這兩個地址:http://localhost/#/user/1
和http://localhost/
其實到服務端都是去請求http://localhost
這個頁面的內容。
而前端的router庫經過捕捉#
號後面的參數、地址,來告訴前端庫(好比Vue)渲染對應的頁面。這樣,無論是咱們在瀏覽器的地址欄輸入,或者是頁面裏經過router的api進行的跳轉,都是同樣的跳轉邏輯。因此這個模式是不須要後端配置其餘邏輯的,只要給前端返回http://localhost
對應的html,剩下具體是哪一個頁面,就由前端路由去判斷即可。
不帶#
號的路由,也就是咱們一般能見到的URL形式。router庫要實現這個功能通常都是經過HTML5提供的history這個api。好比history.pushState()
能夠向瀏覽器地址欄push一個URL,而這個URL是不會向後端發起請求的!經過這個特性,便能很方便地實現漂亮的URL。不過須要注意的是,這個api對於IE9及其如下版本瀏覽器是不支持的,IE10開始支持,因此對於瀏覽器版本是有要求的。vue-router會檢測瀏覽器版本,當沒法啓用history模式的時候會自動降級爲hash模式。
上面說了,你在頁面裏的跳轉,一般是經過router的api去進行的跳轉,router的api調用的一般是history.pushState()
這個api,因此跟後端沒什麼關係。可是一旦你從瀏覽器地址欄裏輸入一個地址,好比http://localhost/user/1
,這個URL是會向後端發起一個get請求的。後端路由表裏若是沒有配置相應的路由,那麼天然就會返回一個404了!這也就是不少朋友在生產模式遇到404頁面的緣由。
那麼不少人會問了,那爲何我在開發模式下沒問題呢?那是由於vue-cli
在開發模式下幫你啓動的那個express
開發服務器幫你作了這方面的配置。理論上在開發模式下原本也是須要配置服務端的,只不過vue-cli
都幫你配置好了,因此你就不用手動配置了。
那麼該如何配置呢?其實在生產模式下配置也很簡單,參考vue-router給出的配置例子。一個原則就是,在全部後端路由規則的最後,配置一個規則,若是前面其餘路由規則都不匹配的狀況下,就執行這個規則——把構建好的那個index.html
返回給前端。這樣就解決了後端路由拋出的404的問題了,由於只要你輸入了http://localhost/user/1
這地址,那麼因爲後端其餘路由都不匹配,那麼就會返回給瀏覽器index.html
。
瀏覽器拿到這個html以後,router庫就開始工做,開始獲取地址欄的URL信息,而後再告訴前端庫(好比Vue)渲染對應的頁面。到這一步就跟hash模式是相似的了。
固然,因爲後端沒法拋出404的頁面錯誤,404的URL規則天然是交給前端路由來決定了。你能夠本身在前端路由裏決定什麼URL都不匹配的404頁面應該顯示什麼。
雖然前端渲染有諸多好處,不過SEO的問題,仍是比較突出的。因此react、vue等框架在後來也在服務端渲染上作着本身的努力。基於前端庫的服務端渲染跟之前基於後端語言的服務端渲染又有所不一樣。前端框架的服務端渲染大多依然採用的是前端路由,而且因爲引入了狀態統1、vnode等等概念,它們的服務端渲染對服務器的性能要求比php等語言基於的字符串填充的模板引擎渲染對於服務器的性能要求高得多。因此在這方面不只是框架自己在不斷改進算法、優化,服務端的性能也必需要有所提高。當初掘金換成SSR的時候也遇到了對應的性能問題,就是這個緣由。
固然在兩者之間,也出現了預渲染的概念。也即先在服務端構建出一部分靜態的html文件,用於直出瀏覽器。而後剩下的頁面再經過經常使用的前端渲染來實現。一般咱們能夠把首頁採用預渲染的方式。這個的好處是明顯的,兼顧了SEO和服務器的性能要求。不過它沒法作到全站SEO,生產構建階段耗時也會有所提升,這也是遺憾所在。
關於預渲染,能夠考慮使用prerender-spa-plugin這個webapck的插件,它的3.x版本開始使用puppeteer來構建html文件了。
得益於前端路由和現代前端框架的完整的先後端渲染能力,跟頁面渲染、組織、組件相關的東西,後端終於能夠不用再參與了。
先後端分離的開發模式也逐漸開始普及。前端開始更加註重頁面開發的工程化、自動化,然後端則更專一於api的提供和數據庫的保障。代碼層面上耦合度也進一步下降,分工也更加明確。咱們也擺脫了當初「刀耕火種」的web開發年代。撒花~
但願經過此文可以讓你對於先後端路由和先後端渲染有所瞭解。在實際開發的過程當中,也不該該僅僅關注於本身所在的領域,相關的領域也要有所涉獵,這樣才能面對問題遊刃有餘。
前端交流羣:928029210