當使用 history 模式的前端路由時靜態(tài)資源服務器配置詳解

前言

對于前端工程師而言,多多少少會碰到按需加載的需求。

比如一個系統(tǒng),需要用戶登陸以后才能使用,對于傳統(tǒng)的前后端未分離的情況,我們一般的處理方式是,當檢測到用戶未登錄的時候,一般會重定向到登錄頁面,讓用戶進行登錄。

但是對于前后端分離的情況,前端工程師一般傾向于單頁面的處理模式,而想要處理這種情況的話,我們一般傳統(tǒng)的做法是,會選擇采用 location.search 的方式,即通過參數來判斷。

比如檢測到用戶沒登陸,我們會刷新頁面,自動在地址后面加上諸如 ?page=login 等形式的參數,然后我們的系統(tǒng)初始化的時候,會檢測 location.search 中是否存在這個參數,如果存在,頁面上顯示的就是登錄有關的內容。

但是這種處理方式寫起來太過復雜,而前端比較流行的框架 vue、react 等給了我們比較好的解決方案。

那就是采用 vue-router 或者 react-router 這種解決方案,一般會有兩種模式,history 模式和 hash 模式,兩種模式對于開發(fā)來說,沒有任何的區(qū)別。

history、hash 模式區(qū)別

這里主要不是想介紹前端 router 的相關內容的,這里就一筆帶過,不做過多的贅述了。

我們知道的是,history 模式,是基于 html5 提供的 history api 來實現的。

對于 react router 來說,它的作用是這樣的:

Browser history 是使用 React Router 的應用推薦的 history。它使用瀏覽器中的 History API 用于處理 URL,創(chuàng)建一個像example.com/some/path這樣真實的 URL 。

而一般所謂的 hash 模式,就是通過來監(jiān)聽 hash 的變化,來改變頁面的視圖的。

對于 react router 來說,他的作用是這樣的:

Hash history 使用 URL 中的 hash(#)部分去創(chuàng)建形如example.com/#/some/path的路由。

到這里,我想以前不了解的童鞋應該會明白了,這篇文章想要表達的內容到底是什么了。

我們打包以后,采用 hash 的前端路由項目,扔在任何服務器里面,是不會存在找不到資源的情況,因為頁面的入口始終都是 example.com/rootpath/ 其他資源都是根據這個路徑來索引的。

但是對于 history 方式的前端路由項目,打包了以后,扔在各種靜態(tài)資源服務器中,是沒有辦法正常使用的。

刨根問底

你如果之前有類似的經歷,那么你肯定上網找過解決方案。網上一找,會有很多教你怎么配置的“攻略”,但是都是流于表面,根本不告訴你為什么這么用,這么用的原理是什么,這么用究竟是要解決什么問題。

弄懂了原理,我們才能對癥下藥,才能在任何靜態(tài)資源服務器中都能舒服的使用我們的 history 路由。

首先,我們來探求,為什么找不到資源的原因。

因為我們一般都是打包以后放在靜態(tài)資源服務器中的,我們訪問諸如 example.com/rootpath/ 這種形式的資源沒問題,是因為,index.html 文件是真實的存在于 rootpath 文件夾中的,可以找到的,返回給前端的。

但是如果訪問子路由 example.com/rootpath/login 進行登錄操作,但是 login/index.html 文件并非真實存在的文件,其實我們需要的文件還是 rootpath 目錄中的 index.html

再者,如果我們需要 js 文件,比如登陸的時候請求的地址是 example.com/rootpath/login/js/dist.js 其實我們想要的文件,還是 rootpath/js/ 目錄中的 dist.js 文件而已。

前端路由其實是一種假象,只是用來蒙蔽使用者而已的,無論用什么路由,訪問的都是同一套靜態(tài)資源。

之所以展示的內容不同,只是因為代碼里,根據不同的路由,對要顯示的視圖做了處理而已。

我相信,說到這里,聰明的童鞋,應該就想明白了,我們該怎么做,才能做到 history 模式的前端路由打包以后照樣能用了。

那就是,一旦匹配子路徑,發(fā)現 404 了,直接將路徑中的子目錄移除掉,返回根目錄種對應的文件即可。

這么說,可能有點拗口,舉幾個例子,可能就比較好理解了。

比如要找 example.com/rootpath/login 靜態(tài)資源服務器找不到,那就返回 example.com/rootpath/ 內容;要找 example.com/rootpath/login/css/style.css 找不到,那就照著 example.com/rootpath/css/style.css 這個路徑去找。

總之就是,請求的是子目錄,找不到,那就返回根目錄一級對應的資源文件就好了。

理是這個理,但是該如何配置呢?

別急,接下來,就將幾種常見的情況下,該如何配置,保證 history 前端路由也能正常使用。

在 nginx 中使用

如果你打包以后的前端靜態(tài)資源文件,想要仍在 nginx 中使用,那首先將你打包好的靜態(tài)資源目錄扔進 www 目錄,比如你打包好的資源的目錄叫 rootpath ,那么直接將 rootpath 整個目錄丟進 www 目錄即可。

然后打開我們的 nginx 配置文件 nginx.conf,插入以下配置:

location /rootpath/ {
    root   html;
    index  index.html index.htm;
    try_files $uri $uri/ /rootpath/index.html;
}

這樣就能保證我們的前端路由能夠正常的訪問了

前端路由訪問.gif

如果要放在根目錄用,直接將配置中的 /rootpath 相關字段從配置中去掉即可。

在 tomcat 中使用

如果在 window 中使用,可以直接下載二進制安裝包,解壓以后,一般直接就能使用。


image.png

一般我們將我們的靜態(tài)資源放在 webapps 文件夾中。

要想達到和上面 nginx 中一樣的效果,首先同樣是將 rootpath 文件夾放進 webapps 中。

然后在 webapps/rootpath 中新建 WEB-INF 文件夾,文件夾里新建一個 web.xml 文件。

文件中內容配置如下即可:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>your_display_name</display-name>

    <error-page>
        <error-code>404</error-code>
        <location>/index.html</location>
    </error-page>

</web-app>

配置好以后,重啟 tomcat,會得到如上圖同樣的效果。

總結反思

其實,很多時候,碰到的問題,多查資料,深究其原理,明白了原理以后,就能找到合適的解決方案。

如果只是機械式地照搬,碰運氣式的嘗試,往往會南轅北轍,很難找到滿意的解決方案。

參考資料

  1. http://react-guide.github.io/react-router-cn/docs/guides/basics/Histories.html
  2. https://www.learninjava.com/react-router-apache-nginx-tomcat/
  3. https://stackoverflow.com/questions/41246261/react-routing-is-able-to-handle-different-url-path-but-tomcat-returns-404-not-av/50460867#50460867
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容