始發於個人博客 ryougifujino.com,歡迎訪問留言。javascript
vue-router
分爲hash
和history
模式,前者爲其默認模式,url的表現形式爲http://yoursite.com#home
,比較難看。後者的url表現形式爲http://yoursite.com/home
,比較美觀。
但若是要使用history
模式,咱們須要在後端進行額外配置。本文將討論如何配置以及爲何要這樣配置。html
history
模式的配置方法咱們來看看官方文檔是教咱們怎麼配置的:HTML5 History 模式。前端
首先要將mode
設置爲history
:vue
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)會默認去目標目錄(這裏爲location
中root
所指定的目錄)下尋找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.html
。vue-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: '/'
)來解決這個問題。