从前端角度谈谈单页应用的 nginx 配置
最近有段時間沒搞項目部署了,結果在部署前端項目的時候,訪問頁面路由(不是根路徑),nginx 響應都是 404,直接訪問頁面根路徑,路由跳轉到前端的 404 頁面,排查了半天,這里再總結一下。
1. 路由訪問 404 問題
前端單頁應用路由分兩種:哈希模式和歷史模式。
哈希模式部署不會遇到啥問題,但是一般只用于本地調試,沒人直接部署到生產環境。歷史模式的路由跳轉通過 pushState 和 replaceState 實現,不會觸發瀏覽器刷新頁面,不會給服務器發送請求,且會觸發 popState 事件,進而監聽路由變化渲染相應頁面組件,因此可以實現純前端路由。
需要注意,使用歷史模式的時候,還是有兩種情況會導致瀏覽器發送請求給服務器:
- 輸入地址直接訪問
- 刷新頁面
在這兩種情況下,如果當前地址不是根路徑,因為都是前端路由,服務器端根本不存在對應的文件,則會直接導致 nginx 直接響應 404。因此需要在服務器端進行配置:
server {listen 80;server_name www.example.com;location / {root /root/workspace/ruoyi-ui/dist;# history 模式重點就是這里try_files $uri $uri/ /index.html;} }try_files 的作用就是按順序檢查文件是否存在,返回第一個找到的文件。$uri 是 nginx 提供的變量,指當前請求的 URI,不包括任何參數
當請求靜態資源文件的時候,命中 $uri 規則;當請求頁面路由的時候,命中 /index.html 規則
至于直接訪問頁面根路徑,會跳轉到前端的 404 頁面,這完全是前端路由配置問題。前端路由配置的時候,沒有給根路徑 / 配置規則,而對匹配不到路由的時候,配置了 404 頁面,所以訪問根路徑會重定向到 404 頁面,這個跳轉是前端操作,與 nginx 無關。正常來說,前端路由配置的時候,都會給根路徑 / 加一個匹配規則,例如根路徑重定向到 index 路由,可以確保用戶訪問根路徑可以正常展示頁面。
2. 非根路徑部署訪問 404 問題
此外,在部署的時候不使用根路徑,例如希望通過這樣的路徑去訪問 /i/top.gif,如果直接修改 location 發現還會響應 404:
location /i/ {root /data/w3;try_files $uri $uri/ /index.html; }這是因為 root 是直接拼接 root + location,訪問 /i/top.gif,實際會查找 /data/w3/i/top.gif 文件
這種情況下推薦使用 alias:
location /i/ {alias /data/w3;try_files $uri $uri/ /index.html; }alias 是用 alias 替換 location 中的路徑,訪問 /i/top.gif,實際會查找 /data/w3/top.gif 文件
3. 接口請求代理
現在頁面部署成功了,但是接口請求會出錯,這是因為還沒有對接口請求進行代理,下面配置一下:
location ^~ /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://192.168.31.101:8080/; }4. 兩點補充
除了匹配請求路徑訪問對應文件之外,還可以配置合理的緩存機制。由于 Webpack 打包會給靜態資源加上哈希值,因此可以合理配置緩存規則,提升用戶體驗:
- html 文件可以配置協商緩存
- 靜態資源文件由于帶有哈希,可以配置一年強緩存,提升資源二次加載速度
再注意下 location 的匹配優先級規則:
- = 表示精確匹配。只有請求的url路徑與后面的字符串完全相等時,才會命中。
- ^~ 表示如果該符號后面的字符是最佳匹配,采用該規則,不再進行后續的查找。
- ~ 表示該規則是使用正則定義的,區分大小寫。
- ~* 表示該規則是使用正則定義的,不區分大小寫。
nginx 的匹配優先順序按照上面的順序進行優先匹配,而且 只要某一個匹配命中直接退出,不再進行往下的匹配。
剩下的普通匹配會按照 最長匹配長度優先級來匹配,就是誰匹配的越多就用誰。
nginx 每條規則都要以分號結尾,可以運行 nginx -tc nginx.conf 查看配置規則是否生效
5. 完整的 nginx 配置
server {listen 80;server_name www.example.com;# html 頁面訪問location /ruoyi/ {# 支持 /ruoyi 子路徑訪問alias /root/workspace/ruoyi-ui/dist;# history 模式重點就是這里try_files $uri $uri/ /index.html;# html 文件不可設置強緩存,設置協商緩存即可add_header Cache-Control 'no-cache, must-revalidate, proxy-revalidate, max-age=0';}# 接口請求代理location ^~ /prod-api/ {proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://192.168.31.101:8080/;}# 靜態資源訪問location ~* \.(?:css(\.map)?|js(\.map)?|gif|svg|jfif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {# 靜態資源設置一年強緩存add_header Cache-Control 'public, max-age=31536000';} }6. 總結
單頁應用歷史模式路由,如果不是根路徑,請求服務器都會響應 404,需要在服務器端配置 try_files 按順序進行匹配,其中請求頁面路由命中 /index.html 規則,請求靜態資源命中 $uri 規則。
當頁面部署在子路徑下的時候,使用 root 會拼接 root + location,使用 alias 則是用 alias 替換 location 中的路徑。
前端項目部署的時候,還需要配置接口請求代理。
給 html 文件配置協商緩存,由于靜態資源文件會帶哈希,因此可以給靜態資源文件配置強緩存。
location 匹配的優先級規則注意下。
參考
前端到底用nginx來做啥
一份簡單夠用的 Nginx Location 配置講解
總結
以上是生活随笔為你收集整理的从前端角度谈谈单页应用的 nginx 配置的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 士不可以不弘毅,任重而道远!
- 下一篇: 【基于Centos】驱动安装