基於ReactRouter實現的SPA應用的Nginx配置

先說一下背景,最近在開發一個自己的SPA應用的時候,使用了React系全家桶,路由使用了ReactRouterV4.0版本,使用了history模式。在本地開發過程中,沒有什麼問題,刷新什麼的非常好使。

但是當該項目開發的進入尾聲的時候,將其部署到伺服器,因為都是靜態資源,所以就直接用nginx做一下資源代理。而且還有一個使用nginx做反代的原因是因為前後端分離,服務端和前端應用部署不在同一個機器上,需要對API進行反代,當然nginx還有其他非常強大的功能,就不一一列舉了。

於是,很快,我就把nginx的配置配好了,如下:

server {n listen 8099;n root /home/ubuntu/r-web/build/;nn charset utf-8;n access_log /var/log/fe.log;nn location /api/v1/ {n proxy_pass http://demo.server.com/api/v1/;n }n }n

大概的意思就是 應用在8099埠號下,靜態資源位於 /home/ubuntu/r-web/build/下,會主動去找該文件夾下的index.html文件,log文件會放在/var/log/fe.log文件下,對於/api/v1/下的api路由會被轉發到 http://demo.server.com/api/v1/下。更多的配置可以大家參考nginx配置的文章。

乍一眼看過來是沒有問題的,我們訪問對應的ip:port也是OK的,但是當我們進入應用的某一個路由時,刷新一下,便看到瀏覽器的「醜惡嘴臉」

發現這個的時候真的是 「天啊,重大的問題啊!」,但是,發現問題,解決問題,是我們的天性,冷靜下來,思考,為什麼本地是OK的,用nginx配置後就失敗了呢?

查閱一番後,發現是因為當該url請求到來時,nginx會去配置里去找對應的匹配,因為他才不管,它也不知道,路由是歸誰管的,它是一個很嚴謹的worker,來了請求它就會去對應的去找該請求,沒有找到就返回默認的404頁面(默認你沒有自己配置),知道原理後我們就去fix這個bug了

首先想到的是將history模式->hash模式,因為路由pathname都是相同的,只是根據hash的不同,交由前端來判斷該邏輯,所以可以完美的解決該問題。但是!!考慮到改動的成本非常的大,以及「美觀性」,所以就放棄了該方案。

第二個方案就是想著把所有的關HTML有關的路由,通過修改nginx配置全部讓他返回index.html,於是就利用了nginx的try_files特性,修改配置如下:

server {n listen 8099;n root /home/ubuntu/r-web/build/;nn charset utf-8;n access_log /var/log/fe.log;nn location /api/v1/ {n proxy_pass http://demo.server.com/api/v1/;n }nn location ^~ /index {n try_files $uri /index.html;n }nn location ^~ /create {n try_files $uri /index.html;n }nn location ^~ /help {n try_files $uri /index.html;n }nn location ^~ /my_center {n try_files $uri /index.html;n }n location ^~ /login {n try_files &uri /index.html;n }n location ^~ /register {n try_files &uri /index.html;n }n location ^~ /resetPassword {n try_files &uri /index.html;n }n # ...n}n

但是這個看起來怪怪的呀,如果業務上再加幾個路由,豈不是又要加上一些配置了,如果忘記加了,豈不是很尷尬,於是想起了使用的ReactRouter的一個很好的屬性 basename, 於是乎 我們的nginx配置就變成了

server {n listen 8099;n root /home/ubuntu/r-web/build/;nn charset utf-8;n access_log /var/log/fe.log;nn location /api/v1/ {n proxy_pass http://demo.server.com/api/v1/;n }nn location ^~ /basename/ {n try_files $uri /index.html;n }n # ...n}n

從此,媽媽再也不用擔心我會忘記加路由還要配置nginx啦!!

在本文的最後,給出兩點tips:

  • 當前後端服務不在一塊,API的路由配置最好有一個公共的前綴,加上一些api的version組合起來,便於後期統一做轉發,以及api的version控制
  • 前端router的設計,特別是SPA應用,最好也能夠根據服務也好,模塊也好,能夠有一個路由的層級關係,無論是維護性、觀察性還是擴展性都是一個不錯的設計。

謝謝大家,如有錯誤,懇請斧正。

推薦閱讀:

Nginx反向代理為什麼可以提高網站性能?
淺談前端線上部署與運維
準確地配置 NginX (1)
HTTP2 折騰記

TAG:Nginx | SPASinglePageApp | reactrouter |