Vue Router history模式的配置方法及其原理

始發於個人博客 ryougifujino.com,歡迎訪問留言。javascript

vue-router分爲hashhistory模式,前者爲其默認模式,url的表現形式爲http://yoursite.com#home,比較難看。後者的url表現形式爲http://yoursite.com/home,比較美觀。
但若是要使用history模式,咱們須要在後端進行額外配置。本文將討論如何配置以及爲何要這樣配置。html

history模式的配置方法

咱們來看看官方文檔是教咱們怎麼配置的:HTML5 History 模式前端

首先要將mode設置爲historyvue

const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

而後設置後端(這裏採用的nginx):java

location / {
  try_files $uri $uri/ /index.html;
}

而後就......沒了!顯然官方的教程講的比較簡略,而且咱們參照這個教程實際上仍是會遇到一些問題。webpack

history模式的配置實踐及原理

強烈建議:閱讀這部分以前,先看一下nginx的這部分文檔這部分文檔nginx

既然官方文檔教咱們這樣作了,咱們就按照它說的來實踐一下。web

只配置前端的狀況

首先,咱們將mode設置爲history,但不配置後端。而後,假如咱們的路由是長這個樣子的:vue-router

const routes = [
    {path: '/home', component: Home},
    {path: '/', redirect: '/home'}
];

咱們用nginx部署項目,而後在地址欄輸入http://localhost:8080(這裏配置的端口是8080),你會發現地址欄以後會變爲http://localhost:8080/home,而且看起來一切正常,彷佛路由也能夠正常切換而不會發生其餘問題(實際上會發生問題,後面會進行討論)。看起來好像不須要按官網告訴咱們的那樣配置後端也能實現history模式,但若是你直接在地址欄輸入http://localhost:8080/home,你會發現你得到了一個404頁面。chrome

那麼http://localhost:8080爲何能夠(部分)正常顯示呢?道理其實很簡單,你訪問http://localhost:8080時,靜態服務器(這裏是nginx)會默認去目標目錄(這裏爲locationroot所指定的目錄)下尋找index.html(這是nginx在端口後沒有額外路徑時的默認行爲),目標目錄下有這個文件嗎?有!而後靜態服務器返回給你這個文件,配合vue-router進行轉發,天然能夠(部分)正常顯示。
但若是直接訪問http://localhost:8080/home,靜態服務器會去目標目錄下尋找home文件,目標目錄下有這個文件嗎?沒有!因此天然就404了。

配置後端

爲了達到直接訪問http://localhost:8080/home也能夠成功的目的,咱們須要對後端(這裏即nginx)進行一些配置。

首先想一想,要怎樣才能達到這個目的呢?

在傳統的hash模式中(http://localhost:8080#home),即便不須要配置,靜態服務器始終會去尋找index.html並返回給咱們,而後vue-router會獲取#後面的字符做爲參數,對前端頁面進行變換。

類比一下,在history模式中,咱們所想要的狀況就是:輸入http://localhost:8080/home,但最終返回的也是index.html,而後vue-router會獲取home做爲參數,對前端頁面進行變換。那麼在nginx中,誰能作到這件事呢?答案就是try_files

首先看一下try_files的語法:try_files file ... uri;
而後看一下官方文檔對它的介紹:

Checks the existence of files in the specified order and uses the first found file for request processing; the processing is performed in the current context. The path to a file is constructed from the file parameter according to the root and alias directives. It is possible to check directory’s existence by specifying a slash at the end of a name, e.g. 「$uri/」. If none of the files were found, an internal redirect to the uri specified in the last parameter is made.

大意就是它會按照try_files後面的參數依次去匹配root中對應的文件或文件夾。若是匹配到的是一個文件,那麼將返回這個文件;若是匹配到的是一個文件夾,那麼將返回這個文件夾中index指令指定的文件。最後一個uri參數將做爲前面沒有匹配到的fallback。(注意try_files指令至少須要兩個參數)

拿我本身的網站舉個例子:

location / { 
        root            /data/www/rf-blog-web; 
        index           index.html; 
        try_files       $uri $uri/ /index.html; 
}
$uri是nginx中的變量,好比我訪問的網址是 http://localhost:8080/home,那麼它就表明的 /home

rf-blog-web這個目錄中,沒有子目錄,只有一個index.html和一些壓縮後的名稱是hash值的.js文件。當咱們請求http://localhost:8080/home這個地址時,首先查找有無home這個文件,沒有;再查找有無home目錄,也沒有。因此最終會定位到第三個參數從而返回index.html,按照這個規則,全部路由裏的url路徑最後都會定位到index.htmlvue-router再獲取參數進行前端頁面的變換,至此,咱們已經能夠經過http://localhost:8080/home這個地址進行成功地訪問了。
$uri這個參數的做用實際上是匹配那些.js文件用的,而$uri/在這個例子中並無多大用,其實是能夠去掉的。

history模式下可能會遇到的問題及解決方案

在將個人項目(在路由中用了懶加載)改成history模式的過程當中,有時候發現會出現chunk加載出錯的狀況,打開chrome的network發現那個chunk加載404了,是由於請求的url中多了一層路徑。我在這裏發現瞭解決方案。

LinusBorg說,由於在history模式中切換路由時,咱們是真正改變了頁面的url路徑,因此webpack的runtime會認爲它位於example.com/some/path。若是publicPath是設置的相對路徑,那麼webpack加載chunk時可能會變成example.com/some/path/static/js/3.js這樣的路徑,然而chunk的真正路徑是example.com/static/js/3.js,因此咱們須要將publicPath設置爲絕對路徑(publicPath: '/')來解決這個問題。

相關文章
相關標籤/搜索