先說初步得到的結論,這只是我根據測試結果的推測,并沒有閱讀源碼探究原因。在nginx如下配置中,有’/index’路由匹配規(guī)則
location /index {
alias /home/hfy/dist;
index index.html;
}
由于’/index’中的index為關鍵字,導致路由匹配發(fā)生異常,與預期不符,把’/index’更改為’/home’,恢復正常
1. 背景介紹
vue項目只有一個組件,路由模式是history,路由中有一個根路徑重定向配置,路由配置如下
const routes = [
{
path: '/',
redirect: '/index'
},
{
path: '/index',
name: 'index',
component: () => import('../views/IndexView.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
vue項目build之后,使用nginx部署build之后的產物,nginx路由配置如下
location / {
root /home/hfy/dist;
index index.html;
}
location /index {
alias /home/hfy/dist;
index index.html;
}
/home/hfy/dist文件夾中存放的是build產物,包含css、fonts、js文件夾以及favicon.ico、index.html
我添加上述 location /index
規(guī)則是想解決刷新頁面后404問題
即通過url: example.com訪問時,加載到index.html之后,前端路由會重定向到example.com/index,這時候刷新頁面,瀏覽器會請求example.com/index。如果不添加location /index
規(guī)則,nginx無法匹配到/index,會返回404。
但是我添加該規(guī)則后遇到了下面的問題一。
2. 問題描述
2.1 問題一
通過url:example.com 訪問該項目,nginx提示404
通過url: example.com/index 訪問該項目,可以正常訪問
2.2 問題二
如果把nginx路由配置更改為
location / {
root /home/hfy/dist;
index index.html;
}
#location /index {
# alias /home/hfy/dist;
# index index.html;
#}
通過url: example.com 訪問該項目,可以正常訪問
通過url: example.com/index 訪問該項目,nginx提示404
3. 原因分析
3.1 問題一
- 通過url: example.com/index 訪問該項目時,命中規(guī)則
location /index {
alias /home/hfy/dist;
index index.html;
}
/home/hfy/dist文件夾中存在index.html,所以訪問的是/home/hfy/dist/index.html
- 通過url: example.com 訪問該項目時,命中規(guī)則
location / {
root /home/hfy/dist;
index index.html;
}
應該能訪問到/home/hfy/dist/index.html,但是卻提示404, 無法理解,在4.排查問題一原因中將介紹如何找到該問題原因
3.2 問題二
問題二我是這樣理解的,location /index規(guī)則被注釋掉不起作用
- 通過url: example.com 訪問項目時,命中規(guī)則
location / {
root /home/hfy/dist;
index index.html;
}
域名會被root替換,訪問的是/home/hfy/dist/中的index.html
- 通過url: example.com/index 訪問項目時,同樣命中上述規(guī)則,域名被root替換,訪問的是/home/hfy/dist/中的index文件或者index文件夾,但是并不存在index文件或者index文件夾,所以報錯404
4. 排查問題一原因
我之前還寫過另一個vue項目,跟這個項目類似,前端路由中同樣使用了history模式以及重定向,nginx配置也類似,但是卻沒有出現404問題,那我就把這兩個項目做對比,排查原因。為了方便敘述,把出404問題的項目叫做項目一,未出問題的項目稱項目二。如下是項目二的配置。
// 前端路由配置
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: () => import('../views/HomeView.vue')
}
]
# nginx配置
location / {
root /home/hfy/other_dist;
index index.html;
}
location /home {
alias /home/hfy/other_dist;
index index.html;
}
我懷疑可能出問題的地方如下
- 由于項目一與項目二vue-router等依賴的版本不同,項目一的index.html可能有問題
- 項目一的nginx虛擬主機配置有問題
為了驗證1,我把項目二nginx配置location /
root指向項目一,發(fā)現可以通過/ 訪問到index.html,說明項目一的index.html文件沒問題
為了驗證2,我把項目一的location
規(guī)則換成項目二的規(guī)則,在更換的過程中,發(fā)現只把location /
root指向項目二,通過/訪問不到項目二,但是把location /index
換成location /home
alias指向項目二,突然可以訪問到項目二了。說明項目一的虛擬主機配置沒問題,這時候也意識到了location /index
中index是關鍵字,關鍵字不能直接寫在location匹配url中
5. 反思
在實際排查問題一時,并不是這么簡單,而是想到什么測試什么,這樣測試比較混亂,容易重復測試,或者漏掉測試,這樣測試得出的結論也不自信,也容易忘記測試的結果。
應該提前想好可能是哪里出現問題了,并一一羅列出來,根據這些問題設計出測試方法,并想好每一種測試結果能推測出的結論。還要及時做記錄,防止遺忘。
發(fā)現瀏覽器隱私模式也會使用緩存,在測試問題前要清理瀏覽器緩存。
6. nginx root與alias的使用
在排查問題時詳細分析了nginx root與alias的用法: 詳解nginx的root與alias
7. 更優(yōu)雅地解決vue網頁瀏覽器刷新404
7.1 try_files
上面的解決方法是在nginx中為vue的一個路由單獨配置location規(guī)則,并依靠alias正確返回index.html文件,即構建好的前端頁面。如果前端路由比較少,這種方法還能夠接受。如果前端有十幾個甚至幾十個路由,就需要在nginx中同步配置這些路由,顯然太麻煩了。
在Vue Router官網中提到了history路由模式下瀏覽器刷新404的問題
當使用這種歷史模式時,URL 會看起來很 “正?!?,例如 https://example.com/user/id 漂亮!
不過,問題來了。由于我們的應用是一個單頁的客戶端應用,如果沒有適當的服務器配置,用戶在瀏覽器中直接訪問 https://example.com/user/id ,就會得到一個 404 錯誤。這就尷尬了。
官方給出了nginx的解決方案
location / {
try_files $uri $uri/ /index.html;
}
try_files指令的詳細解析可以參考文章Nginx的try_files指令詳解,其作用是按順序檢查文件是否存在,返回第一個找到的文件或文件夾(結尾加斜線表示為文件夾),如果所有的文件或文件夾都找不到,會進行一個內部重定向到最后一個參數。
我們以https://example.com/user/id 為例。
try_files首先會在nginx指定的root目錄下尋找$uri文件。假設root設置為/home/hfy/,那么就是尋找/home/hfy/$uri,其中的$uri是url中的路徑,即/user/id。所以最終的訪問路徑是/home/hfy/user/id。
如果不存在id這個文件,就繼續(xù)判斷是否存在/home/hfy/user/id/文件夾。如果仍然不存在,就返回指令的最后一個參數,root文件夾中的/index.html文件,即/home/hfy/index.html
root與alias作用域
我們看到官方給的配置中,并未出現root
location / {
try_files $uri $uri/ /index.html;
}
root可以在location內部指定,只針對該location規(guī)則生效,也可以寫在location外server內,作用域是整個server,但是location內的root會覆蓋掉外部root。如果沒有設置root,默認是nginx安裝目錄的html文件夾。比如我的是/usr/local/nginx/html/
alias只能寫在location內部。
7.2 error_page 404
在nginx設置
error_page 404 /index.html;
同樣可以在刷新時正確返回index.html頁面,這樣做是在投機取巧。雖然返回了正確頁面,但是在瀏覽器控制臺的網絡請求中可以看到響應的狀態(tài)碼仍然是404,所以推薦try_files的方法。
7.3 前端配置404
我們在nginx使用try_files指令解決了404問題,但是也帶來了新的問題。假設用戶訪問前端并不存在的路由比如http://example.com/not/exist ,但nginx仍然返回了index.html,用戶并不知道發(fā)生了404錯誤。這就需要在前端專門提供一個404頁面,當用戶訪問不存在的路由時,展示該頁面。文章來源:http://www.zghlxwxcb.cn/news/detail-475917.html
vue router配置如下文章來源地址http://www.zghlxwxcb.cn/news/detail-475917.html
const HomeView = () => import('@/views/HomeView')
const ErrorView = () => import('@/views/404View')
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: HomeView
},
// 增加404路由與頁面,測試發(fā)現path: '*' 不是必須寫在最后的
{
path: '/404',
component: ErrorView
},
{
path: '*',
redirect: '/404'
}
]
到了這里,關于vue-nginx刷新404問題的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!