上一期我們講了如何在一個新服務器上用Nginx跑起一個前端項目,但是還有很多缺陷,比如我們想在這個Nginx下跑多個項目怎麼辦,spa單頁項目常見的刷新空白原因及處理等等,本篇將一一介紹。
同端口多項目配置
假設我們有兩個單頁項目,一個pc官網,一個mobile官網,我們都想跑在上期8082端口上,這時候發現我們上一期部署的文件夾是直接放在www目錄下的,這可不行,文件全放這下面都不能區分是哪個項目的了,萬一文件夾或者文件名字一樣,就覆蓋掉了。
那麼有兩種方案:
- 各大cli腳手架上都有輸出文件夾的設置,比如vue-cli的
outputDir,這個可以設置文件夾名。 - 在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/mobile和http://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
這個算是一個補充吧,説一下root和alias的區別,畢竟很多配置用的root,請注意alias只能在location中使用,而root可以配置在http,server,location中使用。
其實root和alias都是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