当前位置: 首页 > news >正文

解决.env.production 写死 IP 的问题:Vue + config.json 运行时加载方案

背景:前端常用 .env.production 在构建时写死 API 地址
场景:运维部署时经常不知道目标主机 IP/域名
问题:每次 IP 变动都要重新编译 → 增加运维成本
引出需求:只修改 IP 就能完成部署,不需要重新打包

目录

  • 一、解决方案思路
  • 二、实现步骤
  • 三、打包部署
  • 四、知识补充

一、解决方案思路

1、前端层面

  • 把动态配置从 .env.production 抽离,放到 public/config.json
  • 在应用启动时 fetch 该文件 → 写入 window.__APP _ CONFIG __
  • 业务代码改用 window.__APP _ CONFIG __ 或封装好的 axios 实例获取 baseURL

2、后端层面(Spring Boot)

  • Spring Security 默认拦截所有请求,导致 /config.json 也被保护 → 返回 401
  • 在 security 配置中将 /config.json 加入 permitAll 白名单,确保前端静态资源匿名可访问

二、实现步骤

  1. 新建 public/config.json(存放运行时配置)
{"ENV": "production","VUE_APP_BASE_API": "","VUE_APP_GPU_BASE_URL": "http://10.143.135.91:9001","VUE_APP_AUTO_LOGIN_USER": "admin","VUE_APP_AUTO_LOGIN_PWD": "21232f297a57a5a743894a0e4a801fc3"
}

在这里插入图片描述

  1. 修改 main.js → 应用启动前加载 config.json

在 src/bootstrapConfig.ts 中封装 loadRuntimeConfig
✅ Vue 3(Vite 或 Vue CLI)
src/bootstrapConfig.ts(JS 项目就用 .js)

export type AppConfig = {ENV: stringVUE_APP_BASE_API: stringVUE_APP_GPU_BASE_URL: stringVUE_APP_AUTO_LOGIN_USER: stringVUE_APP_AUTO_LOGIN_PWD: string
}export async function loadRuntimeConfig(): Promise<AppConfig> {const res = await fetch('./config.json', { cache: 'no-store' })if (!res.ok) throw new Error(`load config.json failed: ${res.status}`)const cfg = (await res.json()) as AppConfig;(window as any).__APP_CONFIG__ = cfgreturn cfg
}
export function getConfig(): AppConfig {return (window as any).__APP_CONFIG__ as AppConfig
}

src/main.ts

import { createApp } from 'vue'
import App from './App.vue'
import { loadRuntimeConfig } from './bootstrapConfig'async function bootstrap() {await loadRuntimeConfig()createApp(App).mount('#app')
}
bootstrap()

✅ Vue 2(Vue CLI)

src/bootstrapConfig.js

export async function loadRuntimeConfig() {const res = await fetch('./config.json', { cache: 'no-store' })if (!res.ok) throw new Error('load config.json failed: ' + res.status)window.__APP_CONFIG__ = await res.json()
}
export function getConfig() { return window.__APP_CONFIG__ }

src/main.js

import Vue from 'vue'
import App from './App.vue'
import { loadRuntimeConfig } from './bootstrapConfig'async function bootstrap() {await loadRuntimeConfig()new Vue({ render: h => h(App) }).$mount('#app')
}
bootstrap()
  1. axios 封装:统一读取 ‘__APP_CONFIG __’ 作为 baseURL

src/api/http.ts

import axios from 'axios'const api = axios.create({baseURL: (window as any).__APP_CONFIG__.VUE_APP_BASE_API
})export default api

业务里:

import api from '@/api/http'
// api.get('/xxx')

另一种方式
使用${window.__APP_CONFIG __.VUE_APP_GPU_BASE_URL}
在这里插入图片描述

  1. Spring Security 配置修改:放行 /config.json
public class WebSecurityConfig extends WebSecurityConfigurerAdapter   {........@Overrideprotected void configure(HttpSecurity http) throws Exception {List<String> defaultExcludes = new ArrayList<>();defaultExcludes.add("/");defaultExcludes.add("/#/**");defaultExcludes.add("/static/**");defaultExcludes.add("/swagger-ui.html");defaultExcludes.add("/swagger-ui/**");defaultExcludes.add("/swagger-resources/**");defaultExcludes.add("/doc.html");defaultExcludes.add("/doc.html#/**");defaultExcludes.add("/v3/api-docs/**");defaultExcludes.add("/index.html");defaultExcludes.add("/webjars/**");defaultExcludes.add("/js/**");defaultExcludes.add("/api/device/query/snap/**");defaultExcludes.add("/record_proxy/*/**");defaultExcludes.add("/api/emit");defaultExcludes.add("/favicon.ico");defaultExcludes.add("/api/user/login");defaultExcludes.add("/index/hook/**");defaultExcludes.add("/api/device/query/snap/**");defaultExcludes.add("/index/hook/abl/**");// 👇 新增这一行,允许匿名访问 config.jsondefaultExcludes.add("/config.json");

部署到Spring Boot → 验证只改 config.json 就能适配 IP
在这里插入图片描述
注意:改造后的文件结构

  1. .env.production (最小化)
# just a flag
NODE_ENV=production
VUE_APP_BUILD_VERSION=1.0.0

⚠️ 注意:
VUE_APP_BASE_API、GPU_BASE_URL、账号密码这些 删掉,因为它们要 runtime 配置,不要在这里写。
可以额外放一些编译时常量(例如版本号、构建时间)。

三、打包部署

方案一
在yml文件下添加配置规则,能够读取容器内的文件

spring:web:resources:static-locations: file:/app/static/,classpath:/static/

方案二
在Dockerfile配置文件

ENTRYPOINT ["java", \"-Dspring.web.resources.static-locations=file:/app/static/,classpath:/static/", \"-Dspring.resources.static-locations=file:/app/static/,classpath:/static/", \"-jar","wvp.jar", \"--spring.config.location=/app/config/"]

在这里插入图片描述

👉 -Dspring.resources.static-locations 是 Spring Boot 2.3 及之前的老配置项,
👉 -Dspring.web.resources.static-locations 是 Spring Boot 2.4 及之后的新配置项,作用完全相同,只是命名空间不同。

意思是:

  1. 覆盖默认规则(自己指定顺序)。
  2. 让 Spring Boot 在两个地方找静态资源:
    file:/app/static/ → 容器里的目录(来自宿主机挂载的 /app/static)。
    classpath:/static/ → 打包在 jar 里的 resources/static/。

👉 关键点是:顺序有优先级,Spring Boot 会先从 file:/app/static/ 找,如果找不到,再去 classpath:/static/。

挂载文件(先copy一份到宿主机 然后挂载到容器内部/app/static/)
在这里插入图片描述
然后就会首先读取容器里面的IP
在这里插入图片描述
修改之后重启容器

docker compose up -d --force-recreate

四、知识补充

Spring Boot 静态资源路径设置
如果你不写任何配置,Spring Boot 会自动从以下目录里找静态文件(按顺序):

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/ ✅ 最常见(即你项目里的 src/main/resources/static)
  • classpath:/public/

举个例子:
你把 src/main/resources/static/config.json 打包进 jar → 浏览器访问 http://localhost:8080/config.json 就能拿到。
这是因为 classpath:/static/ 在默认搜索路径里。

http://www.dtcms.com/a/353242.html

相关文章:

  • vsCode如何自定义编辑器背景色
  • 元宇宙与医疗健康:重构诊疗体验与健康管理模式
  • 硬件开发_基于物联网的儿童座椅系统
  • Milvus + Reranker 混合搜索技术方案详细文档
  • 低空无人机系统关键技术与应用前景:SmartMediaKit视频链路的基石价值
  • SyncBackPro 备份及同步软件中的脚本功能简介
  • 直播预告|鸿蒙原生开发与智能工具实战
  • 【译】模型上下文协议(MCP)现已在 Visual Studio 中正式发布
  • ERP如何帮助工业制造行业实现多厂调配
  • 第38次CCF-CSP认证——月票发行(chatgpt5 vs deepseekv3.1)
  • GitHub 宕机自救指南:应急预案与替代平台
  • 锐捷交换机:IF-MIB::ifName 的oid是多少
  • Python包发布与分发策略:从开发到生产的最佳实践(续)
  • 项目:烟雾报警器
  • 高并发内存池(10)-PageCache获取Span(中)
  • 【LeetCode每日一题】48. 旋转图像 240. 搜索二维矩阵 II
  • C/C++ 数据结构 —— 线索二叉树
  • 《联盟》书籍解读总结
  • 基于NXP iMXRT600音频算法开发方法
  • sql mvcc机制
  • PyTorch中的激活函数
  • html pc和移动端共用一个页面,移动端通过缩放达到适配页面,滚动飘窗
  • 实现自己的AI视频监控系统-第二章-AI分析模块3(核心)
  • ffmpeg+opencv交叉编译
  • Office 2024 长期支持版(Mac中文)Word、Execl、PPT
  • 使用Java操作微软 Azure Blob Storage:上传和下载文件
  • AR眼镜 + 视觉大模型在工业巡检的核心应用场景
  • AI赋能前端性能优化:核心技术与实战策略
  • “一带一路软件博览馆2025”香港开幕,金山办公田然:软件正重新定义未来生产力
  • 人机交互如何变革科普展示?哪些技术正成吸睛焦点?