問題倒不難,可是這個問題以前被鬆哥忽略了。前兩天有小夥伴提出這個疑問,我以爲有必要寫篇文章和你們捋一捋這個問題。前端
先來看一個簡短的視頻:vue
視頻地址java
一個簡單的配置就解決掉 404 問題了,接下來,我再來把這件事的前因後果和你們仔細捋一捋。vue-router
在傳統的先後端不分的開發中,權限管理主要經過過濾器或者攔截器來進行(權限管理框架自己也是經過過濾器鏈來實現功能),若是用戶不具有某一個角色或者某一個權限,則沒法訪問某一個頁面。後端
可是在先後端分離中,頁面的跳轉通通交給前端去作,後端只提供數據,這種時候,權限管理不能再按照以前的思路來。瀏覽器
首先要明確一點,前端是展現給用戶看的,全部的菜單顯示或者隱藏目的不是爲了實現權限管理,而是爲了給用戶一個良好的體驗(把用戶沒有權限的按鈕隱藏起來,避免用戶點擊後提示 403,提升用戶體驗),不能依靠前端隱藏控件來實現權限管理,即數據安全不能依靠前端。安全
這就像普通的表單提交同樣,前端作數據校驗是爲了提升效率,提升用戶體驗,後端纔是真正的確保數據完整性。session
因此,真正的數據安全管理是在後端實現的,後端在接口設計的過程當中,就要確保每個接口都是在知足某種權限的基礎上才能訪問,也就是說,不怕將後端數據接口地址暴露出來,即便暴露出來,只要你沒有相應的角色/權限,也是訪問不了的。框架
前端爲了良好的用戶體驗,須要將用戶不能訪問的接口或者菜單隱藏起來。頁面的跳轉,按鈕的隱藏/展現等等,通通在前端來實現。前後端分離
當先後端分離以後,對於前端所承擔的職責,你們可能會面臨一個問題:若是用戶直接在地址攔輸入某一個頁面的路徑,怎麼辦?
此時,若是沒有作任何額外的處理的話,用戶確實能夠經過直接輸入某一個路徑進入到系統中的某一個頁面中,可是,不用擔憂數據泄露問題,由於沒有相關的角色/權限,就沒法訪問相關的接口,即便進入到相關的頁面,也看不到數據。
可是,若是用戶非這樣操做,進入到一個空白的頁面,用戶體驗很差,冒出來一個空白頁面,有的用戶就手足無措了。
此時,咱們可使用 Vue 中的前置路由導航守衛,來監聽頁面跳轉,若是用戶想要去一個未獲受權的頁面,則直接在前置路由導航守衛中將之攔截下來,重定向到登陸頁,或者直接就停留在當前頁,不讓用戶跳轉,也能夠順手再給用戶一點點未獲受權的提示信息。
以 vhr 中的代碼爲例,我在 main.js 中定義了前置路由導航守衛:
router.beforeEach((to, from, next) => { if (to.path == '/') { next(); }else { if (window.sessionStorage.getItem("user")) { initMenu(router, store); next(); }else{ next('/?redirect='+to.path); } } })
這個方法有點相似於 Java 中的過濾器,to 表示要去哪裏,有點像 HttpServletResponse;from 表示從哪來,有點像 HttpServletRequest;next 表示一個請求繼續向下執行的方法,有點相似於 FilterChain。
這裏會監控到全部的頁面路由/跳轉,主要邏輯是這樣:
有這個配置以後,就不怕用戶亂跳轉了,若是沒有登陸隨意輸入一個地址,就會回到登陸頁面。
上面的配置還存在一個 404 問題。
在用戶尚未登陸的時候,若是他在瀏覽器輸入一個不存在的地址,就會自動回到登陸頁面,這沒有問題,可是用戶若是已經登陸了,在瀏覽器輸入一個不存在的地址,這個時候就會發生 404,當你沒作任何定義的時候,所謂的 404 頁面其實就是一片空白。
要解決這個問題,不少小夥伴第一個思路就是能不能在前置路由導航守衛裏邊作一個判斷,當你要跳轉的時候,先去判斷一個跳轉的路徑是否存在,若是存在再去跳轉,不然就不去跳轉。
這個思路看起來沒問題,但實際上還有更簡便的辦法,那就是使用 vue-router 中的動態路由。
舉一個簡單的例子,咱們有一個用戶展現的頁面,這個頁面會根據不一樣的用戶 id 來展現不一樣的用戶數據,因此咱們在 router.js 中能夠按以下方式來定義路由:
routes: [ // 動態路徑參數 以冒號開頭 { path: '/user/:id', component: User } ]
注意這裏標記的參數 id 前面有一個 :
。定義完成後,之後像 /user/1
、/user/2
都會映射到相同的路由。而像地中的 1 、2 等參數,咱們則能夠經過 this.$route.params.id
獲取。
上面這種是設置一個參數,咱們也能夠設置多個參數,咱們能夠參考官方給出的一個表格:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9CBWcZv3-1584424148156)(http://img.itboyhub.com/2020/03/vue-router-1.png)]
若是有多個參數,也能夠經過 this.$route.params
來獲取參數的值。
注意,在動態路由匹配時,若是咱們從 /user/1
切換到 /user/2
,原有的 User 組件是不會銷燬的,這也意味着組件的生命週期鉤子函數不會再被調用,那麼要怎麼刷新數據呢?這個時候咱們能夠採用 beforeRouteUpdate 導航守衛,在導航守衛中完成數據更新:
router.beforeRouteUpdate((to, from, next) => { //刷新數據 })
最後,就是咱們本文要說的 404 問題了。看懂了前面,如何解決 404 其實就很容易明白了。
咱們可使用通配符 *
來匹配任意路徑,例以下面這段匹配格式:
{ // 會匹配全部路徑 path: '*' }
這個匹配規則會匹配到全部路徑,一般就是用來解決前端頁面的 404 問題。也能夠本身定義一些前綴,例以下面這樣:
{ // 會匹配以 `/javaboy-` 開頭的任意路徑 path: '/javaboy-*' }
當咱們使用通配符的時候,能夠經過 this.$route.params.pathMatch
來獲取通配符匹配到的路徑,例如用戶請求路徑是 /javaboy-aaa
,則 this.$route.params.pathMatch
的值就爲 aaa
。
另外還有一個比較重要的點,就是通配符路徑的順序問題。若是路徑帶有通配符,通常來講要放在路由的最後面。