Vite + Vue SPA 在子路径部署(内外网访问+Nginx 反向代理)

Vite + Vue SPA 在子路径部署(内外网访问+Nginx 反向代理)

问题背景

概述

最近部署了一个基于 Vite + Vue.js + Vuetify 的 SPA 项目。

项目并不是部署在根路径,而是部署在子路径:

复制代码
/product-calculate/

同时存在两个访问场景:

我需要内网和外网均能访问系统页面

以下是详细信息

内网访问

复制代码
http://<内网ip>:<项目端口>/product-calculate/

外网访问

复制代码
https://<公网域名>/product-calculate/

此外,由于我的域名只是用来我个人访问的,所以我希望如果直接访问域名,显示我用于占位的"comming soon"。只有访问特定的路径才会显示我的系统页面。

网络结构

复制代码
浏览器
   │
   │
公网 Nginx(反向代理)
   │
   │
内网 Nginx(静态资源 + API代理)
   │
   │
Vue 打包产物 dist

并且 API 服务在内网api网关注册了,名称为:

复制代码
/product-calculate-service/

一、需求总结

最终需要实现:

1️⃣ SPA 子路径部署

复制代码
/product-calculate/

2️⃣ 支持 SPA 刷新

例如:

复制代码
/product-calculate/products

刷新不能 404。

3️⃣ 同时支持内网 + 外网访问

内网:

复制代码
http://<内网ip>:<项目端口>/product-calculate/

外网:

复制代码
https://<公网域名>/product-calculate/

4️⃣ API 统一路径

复制代码
/product-calculate-service/*

5️⃣ 公网通过反向代理访问内网服务


二、遇到的问题

在部署过程中,遇到了几个典型 SPA 部署问题。


1 刷新页面 404

例如访问:

复制代码
/product-calculate/products

刷新后:

复制代码
404 Not Found

原因:

SPA 使用 history 模式 ,服务器并没有 /products 这个真实文件。

解决方案:

Nginx 需要使用:

复制代码
try_files $uri $uri/ /index.html;

让所有不存在的路径回退到 index.html


2 静态资源 404

浏览器报错:

复制代码
GET /product-calculate/assets/js/index.js 404

原因:

Nginx root 路径与子路径不匹配。

解决办法:

使用 rewrite 去掉 /product-calculate 前缀:

复制代码
rewrite ^/product-calculate/(.*)$ /$1 break;

这样:

复制代码
/product-calculate/assets/js/app.js

会映射为:

复制代码
/assets/js/app.js

从而正确找到 dist 中的文件。


3 MIME type 错误

浏览器报错:

复制代码
Failed to load module script: Expected a JavaScript module but server responded with text/html

原因:

JS 文件被 try_files fallback 到 index.html

本质原因依然是 路径解析错误

解决办法:

保证 rewrite 后能正确匹配真实文件路径。


4 公网刷新变成 "comming soon"

刷新:

复制代码
https://<公网域名>/product-calculate/products

返回:

复制代码
comming soon

原因:

公网 Nginx 的:

复制代码
error_page 404 =200 /index.html;

会在 公网服务器本地查找 index.html

但 index.html 在 内网服务器

导致 fallback 到:

复制代码
location /

返回默认页面。

解决办法:

SPA fallback 只在内网处理。

公网只做 反向代理


5 公网 rewrite 导致 404

公网配置:

复制代码
rewrite ^/product-calculate/(.*)$ /$1 break;

导致:

复制代码
/product-calculate/products

被转发为:

复制代码
/products

而内网服务实际路径是:

复制代码
/product-calculate/products

最终 404。

解决办法:

公网 不要 rewrite,直接代理。


三、最终解决方案

采用 双层 Nginx 架构

复制代码
公网 Nginx
   │
   │ proxy_pass
   │
内网 Nginx
   │
   │ try_files (SPA fallback)
   │
Vue dist

四、最终内网 Nginx 配置

复制代码
server {
    listen <项目端口>;
    server_name <内网ip>;

    root /www/wwwroot/vue/product-calculate/dist;
    index index.html;

    location /product-calculate/ {

        # 去掉前缀
        rewrite ^/product-calculate/(.*)$ /$1 break;

        try_files $uri $uri/ /index.html;
    }

    location /product-calculate-service/ {
        proxy_pass http://<内网ip>:<后端网关端口>/product-calculate-service/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

核心逻辑:

复制代码
rewrite → 去掉子路径前缀
try_files → SPA fallback

五、最终公网 Nginx 配置

公网只做 反向代理

复制代码
location ^~ /product-calculate/ {

    proxy_pass http://<内网ip>:<项目端口>;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

API 代理:

复制代码
location /product-calculate-service/ {
    proxy_pass http://<内网ip>:<后端网关端口>/product-calculate-service/;
}

六、最终访问效果

内网访问:

复制代码
http://<内网ip>:<项目端口>/product-calculate/
http://<内网ip>:<项目端口>/product-calculate/products

外网访问:

复制代码
https://<公网域名>/product-calculate/
https://<公网域名>/product-calculate/products

API:

复制代码
/product-calculate-service/*

全部正常。


七、经验总结

部署 SPA 时有三个关键原则:

1 SPA fallback 只在一个地方处理

推荐:

复制代码
内网 Nginx → try_files
公网 Nginx → proxy

否则容易出现:

  • 404
  • MIME type 错误
  • fallback 错乱

2 子路径部署必须处理路径

两种方式:

方案一:

复制代码
rewrite 去掉前缀

方案二:

复制代码
alias

3 反向代理不要随便 rewrite

如果后端本身已经处理路径:

复制代码
proxy_pass 直接转发

不要额外 rewrite。


八、最终架构

复制代码
Browser
   │
   │
<公网域名>
   │
   │  (公网 Nginx)
   │
proxy_pass
   │
   │
<内网ip>:<项目端口>
   │
   │  (内网 Nginx)
   │
try_files
   │
   │
Vue dist

九、适用场景

这套方案适用于:

  • Vue / Vite SPA
  • React SPA
  • 子路径部署
  • 内外网混合访问
  • API 反向代理
  • 单页应用刷新

如果以后部署新的 SPA 项目,只需要修改/product-calculate为你的新路径即可复用整套方案。

相关推荐
|晴 天|7 小时前
Vue 3 + TypeScript + Element Plus 博客系统开发总结与思考
前端·vue.js·typescript
猫3287 小时前
v-cloak
前端·javascript·vue.js
旷世奇才李先生7 小时前
Vue 3\+Vite\+Pinia实战:企业级前端项目架构设计
前端·javascript·vue.js
SoaringHeart9 小时前
Flutter进阶:用OverlayEntry 实现所有弹窗效果
前端·flutter
mfxcyh10 小时前
使用MobaXterm配置nginx
java·服务器·nginx
阿里巴巴首席技术官11 小时前
通过纯Nginx实现一个简单的文件上传功能
运维·nginx
就叫飞六吧11 小时前
Docker Hub 上主流的nginx发行
java·nginx·docker
IT_陈寒11 小时前
Vite静态资源加载把我坑惨了
前端·人工智能·后端
herinspace11 小时前
管家婆实用贴-如何分离和附加数据库
开发语言·前端·javascript·数据库·语音识别
小码哥_常11 小时前
从MVC到MVI:一文吃透架构模式进化史
前端