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为你的新路径即可复用整套方案。

相关推荐
福兮说6 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea6 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨7 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
niucloud-admin7 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
颜进强7 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
今年下半年9 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
郑州光合科技余经理9 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
2601_9623811311 小时前
历史视频朝代更替动效怎么做?把 AE 关键帧换成 AI 分镜动画的实战拆解
人工智能·nginx·音视频
前端snow11 小时前
ai agent --- DeepAgents 中间件
前端
data analyse 45611 小时前
报表能自定义的国内统计工具有哪些
前端·数据分析