芋道项目部署时,前端和门户网站如何通过 Nginx 转发后台接口,而不直接暴露后端地址

在部署芋道项目时,很多人一开始都会直接让前端去请求后端地址,比如:

text 复制代码
http://后端域名/admin-api

或者打包后前端里还残留着:

text 复制代码
http://localhost:48082

这样会带来几个常见问题:

  • 后端地址直接暴露给用户
  • 容易出现跨域问题
  • 前端打包后接口还是请求 localhost
  • 页面刷新后 404
  • 更换后端地址时,还要重新改前端代码

更推荐的做法是:

  • 前端页面访问自己的域名
  • 前端请求接口时,也走自己的域名
  • 由 Nginx 再把接口请求转发到真正的后端服务

这篇文章把这个问题完整讲清楚,包括:

  1. 为什么不能直接写 localhost
  2. 为什么推荐前端走同域名请求
  3. 芋道管理后台前端配置怎么写
  4. 门户网站前端配置怎么写
  5. Nginx 怎么转发
  6. 页面刷新 404 怎么解决
  7. 常见报错怎么排查

一、问题现象

很多人部署完前端后,打开页面会发现:

  • 登录验证码请求失败
  • 接口请求地址还是 localhost
  • 浏览器控制台报错
  • 页面一刷新就 404
  • 明明后端在服务器上运行,前端却请求不到

例如浏览器里出现这样的请求地址:

text 复制代码
http://localhost:48082/admin-api/system/captcha/get

这就是典型问题。

这里一定要明白:

前端页面是在用户浏览器里运行的。

当前端去请求 localhost:48082 时,请求的不是你的服务器,而是用户自己电脑的 localhost

所以用户当然访问不到你服务器上的后端。


二、正确思路:前端请求自己的域名,Nginx 再转发到后端

正确做法不是让前端直接写后端地址,而是这样:

假设:

  • 管理后台前端域名:admin.example.com
  • 门户网站前端域名:www.example.com
  • 后端服务运行在服务器本机:127.0.0.1:48082

那么前端应该这样请求:

管理后台

前端请求:

text 复制代码
https://admin.example.com/admin-api/...

Nginx 转发到:

text 复制代码
http://127.0.0.1:48082/admin-api/...

门户网站

前端请求:

text 复制代码
https://www.example.com/api/...

或者有些项目会写成:

text 复制代码
https://www.example.com/app-api/...

Nginx 转发到:

text 复制代码
http://127.0.0.1:48082/api/...

或者:

text 复制代码
http://127.0.0.1:48082/app-api/...

三、为什么这样做更好

1. 后端地址不用暴露

用户只看到前端自己的域名,看不到真实后端地址和端口。

2. 避免跨域

因为前端和接口都走同一个域名或同源路径,浏览器不会拦截。

3. 更方便管理

以后后端换端口、换机器、换部署方式,只需要改 Nginx,不需要重新改前端代码。

4. 更安全

后端服务甚至可以只监听 127.0.0.1,完全不对公网开放。


四、前端配置文件怎么写

这一部分是很多新手最容易迷糊的地方。

你要记住一个核心原则:

前端不要直接写真实后端地址,而是写接口前缀。

也就是不要写:

js 复制代码
baseURL: 'http://127.0.0.1:48082'

或者:

js 复制代码
baseURL: 'http://后端域名'

而应该写成:

js 复制代码
baseURL: '/admin-api'

或者:

js 复制代码
baseURL: '/api'

这样前端发请求时,请的就是当前站点自己的域名,再由 Nginx 去转发。


五、门户网站前端配置文件示例

你给出的门户配置文件是这样的:

js 复制代码
// 配置文件
export const config = {
  // 开发环境用完整地址,生产环境通过 nginx 转发
  baseURL: '/api',
  default_headers: 'application/json'
};

这个写法其实就是比较标准的生产环境写法

它的意思是:

  • 前端代码里请求接口时,统一走 /api
  • 浏览器实际访问时,会自动拼成当前域名下的 /api
  • Nginx 再把 /api 转发到真正的后端服务

例如:

前端代码里请求:

js 复制代码
config.baseURL + '/user/info'

最终就是:

text 复制代码
/api/user/info

浏览器实际发出的请求是:

text 复制代码
https://www.example.com/api/user/info

然后 Nginx 转发到:

text 复制代码
http://127.0.0.1:48082/api/user/info

门户网站推荐写法

js 复制代码
// 配置文件
export const config = {
  // 生产环境通过 nginx 转发到后端
  baseURL: '/api',
  default_headers: 'application/json'
};

如果你的门户项目开发环境和生产环境要区分

也可以写成这种方式,更容易理解:

js 复制代码
const isDev = process.env.NODE_ENV === 'development';

export const config = {
  baseURL: isDev ? 'http://127.0.0.1:48082/api' : '/api',
  default_headers: 'application/json'
};

这样含义就很清楚:

  • 本地开发时,前端直接请求本地后端
  • 生产环境部署后,前端只请求 /api
  • 由 Nginx 去转发

六、芋道管理后台前端配置文件示例

芋道管理后台通常是 Vite 项目,很多时候会在 .env 文件里配接口地址。

比如原来有人会写成:

env 复制代码
VITE_BASE_URL='http://localhost:48082'
VITE_API_URL=/admin-api

这个就有问题。

因为它会导致前端最终请求:

text 复制代码
http://localhost:48082/admin-api/...

浏览器里这个 localhost 指向的是用户自己电脑,不是服务器。


芋道管理后台推荐写法

env 复制代码
VITE_BASE_URL=''
VITE_API_URL=/admin-api

这样最终拼接出来的地址就是:

text 复制代码
/admin-api/...

浏览器实际访问时会变成:

text 复制代码
https://admin.example.com/admin-api/system/captcha/get

然后由 Nginx 转发到:

text 复制代码
http://127.0.0.1:48082/admin-api/system/captcha/get

芋道后台前端配置的理解方式

如果你的请求封装代码里是这样拼接的:

js 复制代码
baseURL = import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL

那么:

env 复制代码
VITE_BASE_URL=''
VITE_API_URL=/admin-api

最终结果就是:

js 复制代码
'' + '/admin-api' = '/admin-api'

这正是我们想要的效果。


芋道后台环境变量完整示例

env 复制代码
# 开发环境:本地只启动前端项目,依赖开发环境(后端、APP)
NODE_ENV=production

VITE_DEV=true

# 请求路径
VITE_BASE_URL=''

# 文件上传类型:server - 后端上传,client - 前端直连上传,仅支持S3服务
VITE_UPLOAD_TYPE=server

# 接口地址
VITE_API_URL=/admin-api

# 是否删除debugger
VITE_DROP_DEBUGGER=false

# 是否删除console.log
VITE_DROP_CONSOLE=false

# 是否sourcemap
VITE_SOURCEMAP=true

# 打包路径
VITE_BASE_PATH=/

# 输出路径
VITE_OUT_DIR=dist

# 商城H5会员端域名
VITE_MALL_H5_DOMAIN=''

# 验证码的开关
VITE_APP_CAPTCHA_ENABLE=true

# GoView域名
VITE_GOVIEW_URL=''

这里最关键的只有两个:

env 复制代码
VITE_BASE_URL=''
VITE_API_URL=/admin-api

七、管理后台 Nginx 配置示例

假设:

  • 管理后台域名:admin.example.com
  • 前端静态文件目录:/www/wwwroot/admin-web/dist
  • 后端服务:127.0.0.1:48082
nginx 复制代码
server {
    listen 80;
    server_name admin.example.com;

    root /www/wwwroot/admin-web/dist;
    index index.html index.htm;

    # 管理后台接口转发
    location /admin-api/ {
        proxy_pass http://127.0.0.1:48082/admin-api/;
        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_set_header X-Forwarded-Proto $scheme;
    }

    # 如果项目有 websocket,可加这个
    location /infra/ws/ {
        proxy_pass http://127.0.0.1:48082/infra/ws/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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_set_header X-Forwarded-Proto $scheme;
    }

    # 前端单页应用刷新防 404
    location / {
        try_files $uri $uri/ /index.html;
    }
}

八、门户网站 Nginx 配置示例

如果你的门户配置文件里写的是:

js 复制代码
baseURL: '/api'

那 Nginx 就应该把 /api 转发到后端。

假设:

  • 门户网站域名:www.example.com
  • 前端静态文件目录:/www/wwwroot/portal-web/dist
  • 后端服务:127.0.0.1:48082
nginx 复制代码
server {
    listen 80;
    server_name www.example.com;

    root /www/wwwroot/portal-web/dist;
    index index.html index.htm;

    # 门户接口转发
    location /api/ {
        proxy_pass http://127.0.0.1:48082/api/;
        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_set_header X-Forwarded-Proto $scheme;
    }

    # 前端单页应用刷新防 404
    location / {
        try_files $uri $uri/ /index.html;
    }
}

九、前端配置和 Nginx 配置要一一对应

这是最重要的一点之一。

管理后台

如果前端写的是:

env 复制代码
VITE_API_URL=/admin-api

那么 Nginx 就必须写:

nginx 复制代码
location /admin-api/ {
    proxy_pass http://127.0.0.1:48082/admin-api/;
}

门户网站

如果前端写的是:

js 复制代码
baseURL: '/api'

那么 Nginx 就必须写:

nginx 复制代码
location /api/ {
    proxy_pass http://127.0.0.1:48082/api/;
}

不能乱配

比如前端写的是:

js 复制代码
baseURL: '/api'

但 Nginx 却只配了:

nginx 复制代码
location /admin-api/

那前端请求 /api/... 时,Nginx 根本接不住,请求自然就失败了。

所以一定要记住一句话:

前端 baseURL 写什么,Nginx 就要代理什么。


十、后端最好只监听本机

既然前端已经通过 Nginx 转发到后端,那么后端就没必要再对公网暴露。

例如 Spring Boot 可以这样配置:

yaml 复制代码
server:
  port: 48082
  address: 127.0.0.1

这样意味着:

  • 外部用户无法直接访问 48082
  • 只能通过 Nginx 代理访问
  • 更安全,也更规范

十一、为什么页面刷新会 404

很多 Vue 项目部署后,进入某个页面没事,但一刷新就 404。

例如访问:

text 复制代码
https://admin.example.com/system/user

前端路由能正常展示。

但刷新时,浏览器会直接请求服务器上的 /system/user 文件。

服务器发现没有这个真实文件,就返回 404。

解决办法就是:

nginx 复制代码
location / {
    try_files $uri $uri/ /index.html;
}

这句的意思是:

  • 先找真实文件
  • 再找真实目录
  • 都没有就返回 index.html

然后再由 Vue Router 接管页面路由。


十二、常见错误排查

1. 前端还在请求 localhost

说明前端配置没有改对,或者改完后没有重新打包。

重点检查:

芋道后台
env 复制代码
VITE_BASE_URL=''
VITE_API_URL=/admin-api
门户网站
js 复制代码
baseURL: '/api'

2. 页面正常,接口 404

说明 Nginx 没有正确代理接口路径。

检查:

  • 前端写的是 /admin-api 还是 /api
  • Nginx 有没有对应的 location
  • proxy_pass 路径是否一致
  • 后端服务是否真的运行在 127.0.0.1:48082

3. 刷新页面 404

说明没有写:

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

4. 接口返回的是 HTML 页面

这通常说明接口请求没有匹配到代理规则,而是被:

nginx 复制代码
location / {
    try_files $uri $uri/ /index.html;
}

接住了。

本质上就是接口代理规则写错了,或者顺序有问题。


5. 改了 Nginx 配置但没有生效

每次改完配置后,都要执行:

bash 复制代码
nginx -t

检查配置语法。

没问题后再执行:

bash 复制代码
nginx -s reload

重新加载配置。


十三、最容易理解的一套最终方案

管理后台前端配置

env 复制代码
VITE_BASE_URL=''
VITE_API_URL=/admin-api

管理后台 Nginx

nginx 复制代码
location /admin-api/ {
    proxy_pass http://127.0.0.1:48082/admin-api/;
}

门户网站前端配置

js 复制代码
export const config = {
  baseURL: '/api',
  default_headers: 'application/json'
};

门户网站 Nginx

nginx 复制代码
location /api/ {
    proxy_pass http://127.0.0.1:48082/api/;
}

最终效果

管理后台

浏览器请求:

text 复制代码
https://admin.example.com/admin-api/system/captcha/get

Nginx 转发到:

text 复制代码
http://127.0.0.1:48082/admin-api/system/captcha/get
门户网站

浏览器请求:

text 复制代码
https://www.example.com/api/user/info

Nginx 转发到:

text 复制代码
http://127.0.0.1:48082/api/user/info

十四、总结

芋道项目和门户网站在部署时,不要让前端直接写真实后端地址,更不要写 localhost

正确方式是:

  • 前端请求自己的域名
  • 接口使用相对路径,例如 /admin-api/api
  • Nginx 负责把请求转发到真正的后端服务
  • 前端路由通过 try_files 解决刷新 404
  • 后端只监听 127.0.0.1,不直接暴露公网

一句话总结:

前端只认自己的域名,后端由 Nginx 在服务器内部转发。


十五、可直接复制的最简模板

管理后台前端配置

env 复制代码
VITE_BASE_URL=''
VITE_API_URL=/admin-api

管理后台 Nginx

nginx 复制代码
server {
    listen 80;
    server_name admin.example.com;
    root /www/wwwroot/admin-web/dist;
    index index.html;

    location /admin-api/ {
        proxy_pass http://127.0.0.1:48082/admin-api/;
        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_set_header X-Forwarded-Proto $scheme;
    }

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

门户网站前端配置

js 复制代码
export const config = {
  baseURL: '/api',
  default_headers: 'application/json'
};

门户网站 Nginx

nginx 复制代码
server {
    listen 80;
    server_name www.example.com;
    root /www/wwwroot/portal-web/dist;
    index index.html;

    location /api/ {
        proxy_pass http://127.0.0.1:48082/api/;
        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_set_header X-Forwarded-Proto $scheme;
    }

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

相关推荐
Pedantic2 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘2 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆2 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师3 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆3 小时前
VSCode自动格式化三要素
前端
爱勇宝4 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen4 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518137 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode7 小时前
Redis 在生产项目的使用
前端·后端