Vue去掉#,mode: history後打包後訪問首頁報404錯誤,報Loading chunk xxx failed,Unexpected token 錯誤

版本說明:

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,也好看!

總結一下,地址欄有兩種模式:

  1. hash模式:地址欄包含#,#之後的不被獲取
  2. 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 選項 和相關的 router base 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)

  1. 安裝 IIS UrlRewrite
  2. 在你的網站根目錄中創建一個 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'模式

重新打包部署後,系統終於能夠正常訪問所有頁面和資源了,真是不容易!

 

 

手編不易,轉載請註明來源,謝謝!

歡迎評論區留言討論

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章