版本說明:
Vue-cli:2.x
Nginx:1.16.x
Vue去掉URL中的#
我們在訪問Vue項目時,地址欄長這樣:localhost:8080/#/home/index或者10.51.34.153/#/login
地址欄中出現的#,是什麼作用,能不能去掉?
我們先看Vue Router中給的說明:Vue官網鏈接
vue-router
默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,於是當 URL 改變時,頁面不會重新加載。如果不想要很醜的 hash,我們可以用路由的 history 模式,這種模式充分利用
history.pushState
API 來完成 URL 跳轉而無須重新加載頁面。const router = new VueRouter({ mode: 'history', routes: [...] })
當你使用 history 模式時,URL 就像正常的 url,例如
http://yoursite.com/user/id
,也好看!
總結一下,地址欄有兩種模式:
- hash模式:地址欄包含#,#之後的不被獲取
- history模式:具有對url歷史進行修改的功能
那麼我們如何去掉地址欄中的#呢?,正如上述官網說明一下,我們自需要在new VueRouter時添加一行model的配置即可
源代碼如下:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
注:上述代碼添加的位置要根據各位實際項目的router配置文件而定喲!
添加完上述代碼後,重新訪問項目我們就發現地址欄的#消失。
PS:開發過程中,項目運行沒有問題,待打包部署後會出現404等問題,請繼續往下看:
mode: 'history'後訪問首頁報404錯誤
完成上述配置後我們訪問部署在nginx下的系統時,發現報了很多404的錯誤,但這些錯誤在本地開發時沒有發現,如下圖:
其實官網也進行相應的說明和配置例子:Vue官網鏈接
不過這種模式要玩好,還需要後臺配置支持。因爲我們的應用是個單頁客戶端應用,如果後臺沒有正確的配置,當用戶在瀏覽器直接訪問
http://oursite.com/user/id
就會返回 404,這就不好看了。所以呢,你要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個
index.html
頁面,這個頁面就是你 app 依賴的頁面。
所以錯誤本身不在vue項目而是在我們的後端上,我們需要修改後端配置來解決這個問題,
官方例子:
注意:下列示例假設你在根目錄服務這個應用。如果想部署到一個子目錄,你需要使用 Vue CLI 的
publicPath
選項 和相關的 routerbase
property。你還需要把下列示例中的根目錄調整成爲子目錄 (例如用RewriteBase /name-of-your-subfolder/
替換掉RewriteBase /
)。#Apache
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule>
除了
mod_rewrite
,你也可以使用FallbackResource
。#nginx
location / { try_files $uri $uri/ /index.html; }
#原生 Node.js
const http = require('http') const fs = require('fs') const httpPort = 80 http.createServer((req, res) => { fs.readFile('index.htm', 'utf-8', (err, content) => { if (err) { console.log('We cannot open "index.htm" file.') } res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }) res.end(content) }) }).listen(httpPort, () => { console.log('Server listening on: http://localhost:%s', httpPort) })
#基於 Node.js 的 Express
對於 Node.js/Express,請考慮使用 connect-history-api-fallback 中間件。
#Internet Information Services (IIS)
- 安裝 IIS UrlRewrite
- 在你的網站根目錄中創建一個
web.config
文件,內容如下:<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <rule name="Handle History Mode and custom 404/500" stopProcessing="true"> <match url="(.*)" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Rewrite" url="/" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
#Caddy
rewrite { regexp .* to {path} / }
#Firebase 主機
在你的
firebase.json
中加入:{ "hosting": { "public": "dist", "rewrites": [ { "source": "**", "destination": "/index.html" } ] } }
這裏我使用的是nginx,所以安裝官方實例進行了nginx的配置:
修改配置前nginx conf內容:
server {
listen 8003;
server_name localhost;
root html/demo;
location / {
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
}
修改後:
server {
listen 8003;
server_name localhost;
root html/demo;
location / {
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
}
修改後再次訪問服務器的系統,發現404錯誤已被解決。
報Loading chunk xxx failed,Unexpected token < 錯誤
完成nginx配置後,再次系統時發現又出現了下列錯誤,(內心;一朝改配置、bug無限多)
Uncaught SyntaxError: Unexpected token '<'
vendor.414d6cad290f10a9dfeb.js:1 Error: Loading chunk 3 failed.
at HTMLScriptElement.u (manifest.ca82163d0a5dabe8a5f8.js:1)
這個問題原理我也不太清楚,不過安裝以下方式去調整配置後問題解決:
修改項目config/index.js中build的assetsPublicPath值,
修改前:
module.exports = {
dev: {
// 省略其配置內容......
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../demo/index.html'), // 模板文件生成路徑
// Paths
assetsRoot: path.resolve(__dirname, '../demo'), // 打包後文件要存放的路徑
assetsSubDirectory: 'static', // 除了 index.html 之外的靜態資源要存放在assetsRoot下的什麼路徑,
assetsPublicPath: './', // 代表打包後,index.html裏面引用資源前面需要添加的地址
// 省略其他配置內容......
}
}
修改後:
module.exports = {
dev: {
// 省略其配置內容......
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../demo/index.html'), // 模板文件生成路徑
// Paths
assetsRoot: path.resolve(__dirname, '../demo'), // 打包後文件要存放的路徑
assetsSubDirectory: 'static', // 除了 index.html 之外的靜態資源要存放在assetsRoot下的什麼路徑,
assetsPublicPath: '/', // 代表打包後,index.html裏面引用資源前面需要添加的地址
// 省略其他配置內容......
}
}
注:這裏是將assetsPublicPath的值由'./'改爲'/',去掉了.號,網絡上很多配置教程都是使用的'./',那是因爲router使用的是mode: 'hash'模式
重新打包部署後,系統終於能夠正常訪問所有頁面和資源了,真是不容易!
手編不易,轉載請註明來源,謝謝!
歡迎評論區留言討論