深入理解Web路由

1. 什么是路由

在Web開發(fā)過程中炉爆,經(jīng)常會(huì)遇到『路由』的概念蔬浙。那么,到底什么是路由誊爹?簡單來說蹬刷,路由就是URL到函數(shù)的映射。

2. router和route的區(qū)別

route就是一條路由频丘,它將一個(gè)URL路徑和一個(gè)函數(shù)進(jìn)行映射办成,例如:

```

/users? ? ? ? ->? getAllUsers()

/users/count? ->? getUsersCount()


```

這就是兩條路由,當(dāng)訪問/users的時(shí)候搂漠,會(huì)執(zhí)行g(shù)etAllUsers()函數(shù)迂卢;當(dāng)訪問/users/count的時(shí)候,會(huì)執(zhí)行g(shù)etUsersCount()函數(shù)桐汤。

而router可以理解為一個(gè)容器而克,或者說一種機(jī)制,它管理了一組route怔毛。簡單來說员萍,route只是進(jìn)行了URL和函數(shù)的映射,而在當(dāng)接收到一個(gè)URL之后拣度,去路由映射表中查找相應(yīng)的函數(shù)碎绎,這個(gè)過程是由router來處理的。一句話概括就是 “The router routes you to a route“抗果。

3. 服務(wù)器端路由

對(duì)于服務(wù)器來說筋帖,當(dāng)接收到客戶端發(fā)來的HTTP請(qǐng)求,會(huì)根據(jù)請(qǐng)求的URL冤馏,來找到相應(yīng)的映射函數(shù)日麸,然后執(zhí)行該函數(shù),并將函數(shù)的返回值發(fā)送給客戶端宿接。對(duì)于最簡單的靜態(tài)資源服務(wù)器赘淮,可以認(rèn)為,所有URL的映射函數(shù)就是一個(gè)文件讀取操作睦霎。對(duì)于動(dòng)態(tài)資源,映射函數(shù)可能是一個(gè)數(shù)據(jù)庫讀取操作走诞,也可能是進(jìn)行一些數(shù)據(jù)的處理副女,等等。

Express為例蚣旱,

app.get('/',(req,res)=>{res.sendFile('index')})app.get('/users',(req,res)=>{db.queryAllUsers().then(data=>res.send(data))})

這里定義了兩條路由:

當(dāng)訪問/的時(shí)候碑幅,會(huì)返回index頁面

當(dāng)訪問/users的時(shí)候戴陡,會(huì)從數(shù)據(jù)庫中取出所有用戶數(shù)據(jù)并返回

不僅僅是URL

在router匹配route的過程中,不僅會(huì)根據(jù)URL來匹配沟涨,還會(huì)根據(jù)請(qǐng)求的方法來看是否匹配恤批。例如上面的例子,如果通過POST方法來訪問/users裹赴,就會(huì)找不到正確的路由喜庞。

4. 客戶端路由

對(duì)于客戶端(通常為瀏覽器)來說,路由的映射函數(shù)通常是進(jìn)行一些DOM的顯示和隱藏操作棋返。這樣延都,當(dāng)訪問不同的路徑的時(shí)候,會(huì)顯示不同的頁面組件睛竣∥浚客戶端路由最常見的有以下兩種實(shí)現(xiàn)方案:

基于Hash

基于History API

(1) 基于Hash

我們知道,URL中#及其后面的部分為hash射沟。例如:

consturl=require('url')vara=url.parse('http://example.com/a/b/#/foo/bar')console.log(a.hash)// => #/foo/bar

hash僅僅是客戶端的一個(gè)狀態(tài)殊者,也就是說,當(dāng)向服務(wù)器發(fā)請(qǐng)求的時(shí)候验夯,hash部分并不會(huì)發(fā)過去猖吴。

通過監(jiān)聽window對(duì)象的hashChange事件,可以實(shí)現(xiàn)簡單的路由簿姨。例如:

window.onhashchange=function(){varhash=window.location.hashvarpath=hash.substring(1)switch(path){case'/':showHome()breakcase'/users':showUsersList()breakdefault:show404NotFound()}}

(2) 基于History API

通過HTML5 History API可以在不刷新頁面的情況下距误,直接改變當(dāng)前URL。詳細(xì)用法可以參考:

Manipulating the browser history

Using the HTML5 History API

我們可以通過監(jiān)聽window對(duì)象的popstate事件扁位,來實(shí)現(xiàn)簡單的路由:

window.onpopstate=function(){varpath=window.location.pathnameswitch(path){case'/':showHome()breakcase'/users':showUsersList()breakdefault:show404NotFound()}}

但是這種方法只能捕獲前進(jìn)或后退事件准潭,無法捕獲pushState和replaceState,一種最簡單的解決方法是替換pushState方法域仇,例如:

varpushState=history.pushStatehistory.pushState=function(){pushState.apply(history,arguments)// emit a event or just run a callbackemitEventOrRunCallback()}

不過刑然,最好的方法還是使用實(shí)現(xiàn)好的history庫。

(3) 兩種實(shí)現(xiàn)的比較

總的來說暇务,基于Hash的路由泼掠,兼容性更好;基于History API的路由垦细,更加直觀和正式择镇。

但是,有一點(diǎn)很大的區(qū)別是括改,基于Hash的路由不需要對(duì)服務(wù)器做改動(dòng)腻豌,基于History API的路由需要對(duì)服務(wù)器做一些改造。下面來詳細(xì)分析。

假設(shè)服務(wù)器只有如下文件(script.js被index.html所引用):

/-

|- index.html

|- script.js

基于Hash的路徑有:

http://example.com/

http://example.com/#/foobar

基于History API的路徑有:

http://example.com/

http://example.com/foobar

當(dāng)直接訪問http://example.com/的時(shí)候吝梅,兩者的行為是一致的虱疏,都是返回了index.html文件。

當(dāng)從http://example.com/跳轉(zhuǎn)到http://example.com/#/foobar或者h(yuǎn)ttp://example.com/foobar的時(shí)候苏携,也都是正常的做瞪,因?yàn)榇藭r(shí)已經(jīng)加載了頁面以及腳本文件,所以路由跳轉(zhuǎn)正常右冻。

當(dāng)直接訪問http://example.com/#/foobar的時(shí)候装蓬,實(shí)際上向服務(wù)器發(fā)起的請(qǐng)求是http://example.com/,因此會(huì)首先加載頁面及腳本文件国旷,接下來腳本執(zhí)行路由跳轉(zhuǎn)矛物,一切正常。

當(dāng)直接訪問http://example.com/foobar的時(shí)候跪但,實(shí)際上向服務(wù)器發(fā)起的請(qǐng)求也是http://example.com/foobar履羞,然而服務(wù)器端只能匹配/而無法匹配/foobar,因此會(huì)出現(xiàn)404錯(cuò)誤屡久。

因此如果使用了基于History API的路由忆首,需要改造服務(wù)器端,使得訪問/foobar的時(shí)候也能返回index.html文件被环,這樣當(dāng)瀏覽器加載了頁面及腳本之后糙及,就能進(jìn)行路由跳轉(zhuǎn)了。

5. 動(dòng)態(tài)路由

上面提到的例子都是靜態(tài)路由筛欢,也就是說浸锨,路徑都是固定的。但是有時(shí)候我們需要在路徑中傳入?yún)?shù)版姑,例如獲取某個(gè)用戶的信息柱搜,我們不可能為每個(gè)用戶創(chuàng)建一條路由,而是在通過捕獲路徑中的參數(shù)(例如用戶id)來實(shí)現(xiàn)剥险。

例如在Express中:

app.get('/user/:id',(req,res,next)=>{// ... ...})

Flask中:

@app.route('/user/')defget_user_info(user_id):pass

6. 嚴(yán)格路由

在很多情況下聪蘸,會(huì)遇到/foobar和/foobar/的情況,它們看起來非常類似表制,然而實(shí)際上有所區(qū)別健爬,具體的行為也是視服務(wù)器設(shè)置而定。

Flask的文檔中么介,提到娜遵,末尾有斜線的路徑,類比于文件系統(tǒng)的一個(gè)目錄壤短;末尾沒有斜線的路徑魔熏,類比于一個(gè)文件衷咽。因此訪問/foobar的時(shí)候鸽扁,可能會(huì)重定向到/foobar/蒜绽,而反過來則不會(huì)。

如果使用的是Express桶现,默認(rèn)這兩者是一樣的躲雅,也可以通過app.set來設(shè)置strict routing,來區(qū)別對(duì)待這兩種情況骡和。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末相赁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慰于,更是在濱河造成了極大的恐慌钮科,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婆赠,死亡現(xiàn)場離奇詭異绵脯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)休里,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門蛆挫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妙黍,你說我怎么就攤上這事悴侵。” “怎么了拭嫁?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵可免,是天一觀的道長。 經(jīng)常有香客問我做粤,道長浇借,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任驮宴,我火速辦了婚禮逮刨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堵泽。我一直安慰自己修己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布迎罗。 她就那樣靜靜地躺著睬愤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纹安。 梳的紋絲不亂的頭發(fā)上尤辱,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天砂豌,我揣著相機(jī)與錄音,去河邊找鬼光督。 笑死阳距,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的结借。 我是一名探鬼主播筐摘,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼船老!你這毒婦竟也來了咖熟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤柳畔,失蹤者是張志新(化名)和其女友劉穎馍管,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體薪韩,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡确沸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了躬存。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片张惹。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖岭洲,靈堂內(nèi)的尸體忽然破棺而出宛逗,到底是詐尸還是另有隱情,我是刑警寧澤盾剩,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布雷激,位于F島的核電站,受9級(jí)特大地震影響告私,放射性物質(zhì)發(fā)生泄漏屎暇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一驻粟、第九天 我趴在偏房一處隱蔽的房頂上張望根悼。 院中可真熱鬧,春花似錦蜀撑、人聲如沸挤巡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矿卑。三九已至,卻和暖如春沃饶,著一層夾襖步出監(jiān)牢的瞬間母廷,已是汗流浹背轻黑。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留琴昆,地道東北人氓鄙。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像椎咧,于是被迫代替她去往敵國和親玖详。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容