Vue history模式刷新頁面404問題及解決
為什么會(huì)出現(xiàn)404
我們先來看一下我們給到后端的dist
文件
可以看到dist下只有一個(gè) index.html
文件及一些靜態(tài)資源,這個(gè)是因?yàn)?code>Vue是單頁應(yīng)用(SPA),只有一個(gè)index.html
作為入口文件,其它的路由都是通過JS來進(jìn)行跳轉(zhuǎn)
接著我們?cè)賮矸治鲆幌潞蠖?nginx
的配置
server { // 監(jiān)聽80端口 listen 80; // 定義你的站點(diǎn)名稱 server_name website.com; // 根據(jù)請(qǐng)求 URI 設(shè)置配置 location / { // 站點(diǎn)根目錄,這里為 vue 構(gòu)建出來的 dist 目錄 root /www/dist; // 站點(diǎn)初始頁為index.html 或 index.htm index index.html index.htm; } }
我們現(xiàn)在可以根據(jù) nginx 配置得出,當(dāng)我們?cè)诘刂窓谳斎?website.com 時(shí),這時(shí)會(huì)打開我們 dist 目錄下的 index.html 文件,然后我們?cè)谔D(zhuǎn)路由進(jìn)入到 website.com/login
關(guān)鍵在這里,當(dāng)我們?cè)?website.com/login 頁執(zhí)行刷新操作,nginx location 是沒有相關(guān)配置的,所以就會(huì)出現(xiàn) 404 的情況
為什么hash模式下沒有問題
router hash 模式我們都知道是用符號(hào)#
表示的,如 website.com/#/login, hash 的值為 #/login
它的特點(diǎn)在于:hash 雖然出現(xiàn)在 URL 中,但不會(huì)被包括在 HTTP 請(qǐng)求中,對(duì)服務(wù)端完全沒有影響,因此改變 hash 不會(huì)重新加載頁面
hash 模式下,僅 hash 符號(hào)之前的內(nèi)容會(huì)被包含在請(qǐng)求中,如 website.com/#/login 只有 website.com 會(huì)被包含在請(qǐng)求中 ,因此對(duì)于服務(wù)端來說,即使沒有配置location,也不會(huì)返回404錯(cuò)誤
單頁應(yīng)用(SPA)概念
我們前面有提到單頁應(yīng)用,那什么是單頁應(yīng)用呢?
單頁應(yīng)用
單頁應(yīng)用(single-page application),縮寫SPA 是一種網(wǎng)絡(luò)應(yīng)用程序或網(wǎng)站的模型,它通過動(dòng)態(tài)重寫當(dāng)前頁面來與用戶交互,而非傳統(tǒng)的從服務(wù)器重新加載整個(gè)新頁面。
這種方法避免了頁面之間切換打斷用戶體驗(yàn),使應(yīng)用程序更像一個(gè)桌面應(yīng)用程序。在單頁應(yīng)用中,所有必要的代碼(HTML、JavaScript和CSS)都通過單個(gè)頁面的加載而檢索,或者根據(jù)需要(通常是為響應(yīng)用戶操作)動(dòng)態(tài)裝載適當(dāng)?shù)馁Y源并添加到頁面。
盡管可以用位置散列或HTML5歷史API來提供應(yīng)用程序中單獨(dú)邏輯頁面的感知和導(dǎo)航能力,但頁面在過程中的任何時(shí)間點(diǎn)都不會(huì)重新加載,也不會(huì)將控制轉(zhuǎn)移到其他頁面
大白話來講:
一個(gè)杯子,早上裝的牛奶,中午裝的是開水,晚上裝的是茶,我們可以發(fā)現(xiàn),變的始終是內(nèi)容,而容器還是那個(gè)容器
當(dāng)然,每種技術(shù)都有其利弊,單頁應(yīng)用也是如此
利:
- 無刷新體驗(yàn),這個(gè)應(yīng)該是最顯著的有點(diǎn),由于路由分發(fā)直接在瀏覽器端完成,頁面是不刷新,對(duì)用戶的響應(yīng)非常及時(shí),因此提升了用戶體驗(yàn)
- 完全的前端組件化,前端開發(fā)不再以頁面為單位,更多地采用組件化的思想,代碼結(jié)構(gòu)和組織方式更加規(guī)范化,便于修改和調(diào)整
弊:
- 首屏較長,要在一個(gè)頁面上為用戶提供產(chǎn)品的所有功能,在這個(gè)頁面加載的時(shí)候,首先要加載大量的靜態(tài)資源,這個(gè)加載時(shí)間相對(duì)比較長
- 不利于 SEO,單頁頁面,數(shù)據(jù)在前端渲染,就意味著沒有 SEO,或者需要使用變通的方案
Router的實(shí)現(xiàn)
為了讓大家加深大家對(duì) Router 的理解,這里我們實(shí)現(xiàn)一個(gè)最簡潔的 Router
- hash 模式
核心通過監(jiān)聽url中的hash來進(jìn)行路由跳轉(zhuǎn)
// 定義 Router class Router { constructor () { this.routes = {}; // 存放路由path及callback this.currentUrl = ''; // 監(jiān)聽路由change調(diào)用相對(duì)應(yīng)的路由回調(diào) window.addEventListener('load', this.refresh, false); window.addEventListener('hashchange', this.refresh, false); } route(path, callback){ this.routes[path] = callback; } push(path) { this.routes[path] && this.routes[path]() } } // 使用 router window.miniRouter = new Router(); miniRouter.route('/', () => console.log('page1')) miniRouter.route('/page2', () => console.log('page2')) miniRouter.push('/') // page1 miniRouter.push('/page2') // page2
- history 模式
history 模式核心借用 HTML5 history api,api 提供了豐富的 router 相關(guān)屬性
先了解一個(gè)幾個(gè)相關(guān)的api
- history.pushState 瀏覽器歷史紀(jì)錄添加記錄
- history.replaceState 修改瀏覽器歷史紀(jì)錄中當(dāng)前紀(jì)錄
- history.popState 當(dāng) history 發(fā)生變化時(shí)觸發(fā)
// 定義 Router class Router { constructor () { this.routes = {}; this.listerPopState() } init(path) { history.replaceState({path: path}, null, path); this.routes[path] && this.routes[path](); } route(path, callback){ this.routes[path] = callback; } push(path) { history.pushState({path: path}, null, path); this.routes[path] && this.routes[path](); } listerPopState () { window.addEventListener('popstate' , e => { const path = e.state && e.state.path; this.routers[path] && this.routers[path]() }) } } // 使用 Router window.miniRouter = new Router(); miniRouter.route('/', ()=> console.log('page1')) miniRouter.route('/page2', ()=> console.log('page2')) // 跳轉(zhuǎn) miniRouter.push('/page2') // page2
解決404
看到這里我相信大部分同學(xué)都能想到怎么解決問題了,
產(chǎn)生問題的本質(zhì)是因?yàn)槲覀兊穆酚墒峭ㄟ^JS來執(zhí)行視圖切換的,
當(dāng)我們進(jìn)入到子路由時(shí)刷新頁面,web容器沒有相對(duì)應(yīng)的頁面此時(shí)會(huì)出現(xiàn)404
所以我們只需要配置將任意頁面都重定向到 index.html,把路由交由前端處理
還是以 nginx 為例,更多版本的大家可以前往https://router.vuejs.org/zh/guide/essentials/history-mode.html 查看
location / { try_files $uri $uri/ /index.html; }
這里有一個(gè)小細(xì)節(jié),如果出現(xiàn)真的 404 頁面了呢?比如 website.com/notfound
因?yàn)檫@么做以后,你的服務(wù)器就不再返回 404 錯(cuò)誤頁面,因?yàn)閷?duì)于所有路徑都會(huì)返回 index.html 文件。為了避免這種情況,你應(yīng)該在 Vue 應(yīng)用里面覆蓋所有的路由情況,然后在給出一個(gè) 404 頁面
const router = new VueRouter({ mode: 'history', routes: [ { path: '*', component: NotFoundComponent } ] })
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue3使用MD5加密實(shí)戰(zhàn)案例(清晰明了)
MD5是一種信息摘要算法(對(duì)稱加密),一種被廣泛使用的密碼散列函數(shù),可以產(chǎn)生出一個(gè)128位(16字節(jié))的散列值,用來確保信息傳輸完整一致性,這篇文章主要給大家介紹了關(guān)于Vue3使用MD5加密的相關(guān)資料,需要的朋友可以參考下2023-05-05vue點(diǎn)擊按鈕實(shí)現(xiàn)讓頁面的某一個(gè)元素全屏展示
這篇文章主要介紹了vue點(diǎn)擊按鈕實(shí)現(xiàn)讓頁面的某一個(gè)元素全屏展示,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10vue3+ts+Vuex中使用websocket協(xié)議方式
這篇文章主要介紹了vue3+ts+Vuex中使用websocket協(xié)議方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10尤雨溪開發(fā)vue?dev?server理解vite原理
這篇文章主要為大家介紹了尤雨溪開發(fā)的玩具vite,vue-dev-server來理解vite原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Vue-router結(jié)合transition實(shí)現(xiàn)app前進(jìn)后退動(dòng)畫切換效果的實(shí)例
下面小編就為大家?guī)硪黄猇ue-router結(jié)合transition實(shí)現(xiàn)app前進(jìn)后退動(dòng)畫切換效果的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10vue3 中使用vue?img?cutter?圖片裁剪插件的方法
這篇文章主要介紹了vue3 中使用vue?img?cutter?圖片裁剪插件的方法,首先安裝依賴,構(gòu)建 components/ImgCutter.vue 組件,需要的朋友可以參考下2024-05-05基于 Vue.js 之 iView UI 框架非工程化實(shí)踐記錄(推薦)
為了快速體驗(yàn) MVVM 模式,我選擇了非工程化方式來起步,并選擇使用 Vue.js,以及基于它構(gòu)建的 iView UI 框架。本文給大家分享基于 Vue.js 之 iView UI 框架非工程化實(shí)踐記錄,需要的朋友參考下吧2017-11-11