動態

詳情 返回 返回

Nginx配置單頁應用 - 動態 詳情

上一期我們講了如何在一個新服務器上用Nginx跑起一個前端項目,但是還有很多缺陷,比如我們想在這個Nginx下跑多個項目怎麼辦,spa單頁項目常見的刷新空白原因及處理等等,本篇將一一介紹。

同端口多項目配置

假設我們有兩個單頁項目,一個pc官網,一個mobile官網,我們都想跑在上期8082端口上,這時候發現我們上一期部署的文件夾是直接放在www目錄下的,這可不行,文件全放這下面都不能區分是哪個項目的了,萬一文件夾或者文件名字一樣,就覆蓋掉了。

那麼有兩種方案:

  1. 各大cli腳手架上都有輸出文件夾的設置,比如vue-cli的outputDir,這個可以設置文件夾名。
  2. 在www目錄下新建對應項目的文件夾,scp上傳上傳到對應文件夾。

這裏我們使用一下方案1,方案二類似,路徑不同而已。

修改打包配置

由於我們是在同一個端口下跑的項目,那麼我們只能通過路徑區分不同項目。

比如我們的項目在http://localhost:8082/mobile下跑,那麼vue-router添加base配置:

new VueRouter({
  mode: 'history',
  base: '/mobile', // pc同理
  ...
)}

當然我更建議你把這個路徑值放入.env文件裏,.env.dev:

BASE_URL=/mobile

修改配置為:

new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  ...
)}

// history: createWebHistory(process.env.BASE_URL) // 4.0+

vue.config.js:

module.exports = {
  publicPath: process.env.BASE_URL,  // 這個是打包後外部文件鏈接追加值,比如'/mobile',那麼最後的js和css鏈接為'/mobile/js/xxxx.js'
  outputDir: 'mobile', // 這個是打包輸出文件夾名
  ...
}

進行項目打包,會得到一個mobile文件夾,我們使用scp進行文件上傳(pc同理)

scp -r ./mobile root@$host:~/nginx/www/;  # 上傳mobile文件

Nginx配置修改

location /pc {
  alias   /usr/share/nginx/html/pc/;
  index  index.html;
}

location /mobile {
  alias   /usr/share/nginx/html/mobile/;
  index  index.html;
}

重啓nginx,docker restart web,此時訪問http://localhost:8082/mobile/,網頁能正常打開,當時我們訪問http://localhost:8082/mobile卻發現被詭異的重定向到了80端口,也就是http://localhost/mobile/,查看一下瀏覽器請求發現被301永久重定向了。

這是由於Nginx在訪問URI時;如果訪問資源為一個目錄,且結尾沒有/,那麼Nginx會進行一個301重定向到結尾帶有'/'的地址,跳轉時可以通過port_in_redirec設置跳轉端口號,沒有的話則從listen裏取,也就是80,故這裏進行了80的重定向,我們可以在server模塊中添加absolute_redirect off;關閉這個重定向。

設置之後重啓Nginx,我們通過http://localhost/mobilehttp://localhost/pc都能訪問對應項目。

spa單頁跳轉刷新白屏

我們在上面進行了多項目配置,但是還有一個問題沒有解決,這個問題很常見,就是跳轉後刷新的白屏問題,很多同學不敢從hash路由切換到history路由也是有此原因。

簡單描述一下問題吧:我們直接打開項目的根路徑地址訪問正常,比如上面的http://localhost/mobile,刷新也正常顯示,我們點擊跳轉到http://localhost/mobile/list,此時也正常跳轉,但是我們在這個地址進行原地刷新時,會出現404錯誤,或者説我們直接用瀏覽器打開http://localhost/mobile/list也會出現404,這個問題呢算比較嚴重的了,也就是我們能直接打開或者刷新的只有根路徑,其他路徑都會出現404的問題。

404的原因

首先我們的網頁訪問都是一個get請求,你可以理解為獲取一個靜態資源,我們看一下Nginx的location配置:

location /pc {
  alias   /usr/share/nginx/html/pc/;
  index  index.html;
}

當我們的URI地址匹配到了/pc,會在alias的路徑中查找,默認文件去找index指令後面的的index.html,比如我們訪問http://localhost/mobile能正常訪問,是因為mobile目錄下確實有index.html這個實體文件,那麼正常返回了,而訪問http://localhost/mobile/list,Nginx就會去找mobile/list/index.html,很顯然沒有這個東西,故返回404。

總結一下就是:spa的路由是由js生成的,並不會有對應路徑的實體文件,而Nginx訪問網頁的實體資源,找不到就會返回404,那麼也就是這個路徑是交由我們的js來處理,而不是交由Nginx處理,所以我們只需要在Nginx找不到路徑的實體文件時把我們的index.html返回回去就行了。

location /pc {
  alias   /usr/share/nginx/html/pc/;
  try_files $uri $uri/ /pc/index.html;
  index  index.html;
}

try_files指令會依次查找後面的文件,直到找不到,$uri是原地址,$uri/$uri/index.html,剩下的就是/pc/index.html,舉個例子http://localhost/pc/aaa.png,會先去查找http://localhost/pc/aaa.png,找不到的話查詢http://localhost/pc/aaa.png/index.html,最後則是http://localhost/pc/index.html

ok,這樣spa白屏問題就解決了,但是還有一個微小的問題,那就是當我們訪問的路徑確實不存在(spa-router也沒有),路徑不是Nginx處理了,那麼此時404也就不存在了,會出現白屏,不過聰明的同學已經想到了眾多router都會在最後加個通配符來匹配404的頁面,那麼404的頁面也就交給我們自己寫了。

root和alias

這個算是一個補充吧,説一下rootalias的區別,畢竟很多配置用的root,請注意alias只能在location中使用,而root可以配置在httpserverlocation中使用。

其實rootalias都是Nginx指定文件路徑的指令,以上面的例子:

# root
location /pc {
  root   /usr/share/nginx/html;
  try_files $uri $uri/ /pc/index.html;
  index  index.html;
}
# alias
location /pc {
  alias   /usr/share/nginx/html/pc/;
  try_files $uri $uri/ /pc/index.html;
  index  index.html;
}

這兩個的匹配規則一樣的,簡單來説就是root會把location後面配置的路徑加上,alias則是去除掉,也就是説二者的文件路徑都是指向根目錄下的pc文件夾,也就是説使用root的location匹配的路徑必須真實存在(因為追加了),如果root出現404了直接看path的目錄是否存在就行了。

不過需要注意一點就是alias的路徑結尾需要有個/,雖然這裏加不加都沒問題,但這是一個良好的習慣,請保持,否則遇到下面這種情況就會出錯。以下面例子分別訪問http://localhost:8082/image/logo.png,最後一個會404:

location /image/ {
  alias   /usr/share/nginx/html/image/;
}
location /image {
  alias   /usr/share/nginx/html/image/;
}
location /image {
  alias   /usr/share/nginx/html/image;
}
location /image/ { # 這裏會404
  alias   /usr/share/nginx/html/image;
}

下一篇我會介紹單頁應用在Nginx上的加載優化,盡請期待。

本系列更新只有利用週末和下班時間整理,比較多的內容的話更新會比較慢,希望能對你有所幫助,請多多star或點贊收藏支持一下

本文地址:https://xuxin123.com/web/nginx-spa

Add a new 評論

Some HTML is okay.