Files
xiaotutongxue/frontend-mp/src/config/index.ts
T
lovife 2ff17cd0c9 refactor(h5)!: H5 改由 nginx 托管,后端退回纯 API
用户决定:后端不再对外发静态文件,学生端 H5 交给网关。两者**仍然同源**
(微信只给一个授权回调域名;H5 的接口地址取自 location.origin),
所以前端业务代码、微信后台、application-dev.yml 的 h5-base-url 都不用改。

后端
- 删掉 dev/test/prod 三份 profile 里的 spring.web.resources.static-locations
- 主配置加 spring.web.resources.add-mappings=false —— 用开关而不是"指到空目录":
  后者会连带启用 Spring Boot 的默认位置(classpath:/static 等),谁丢个文件进去就悄悄对外可见
- StaticCacheHeaderFilter → ApiNoStoreFilter,只剩 /api/** 的 no-store
  (静态资源的缓存策略整体归 nginx,避免"改一处漏一处")
- 补 NoHandlerFoundException → 404:关掉静态映射后未匹配路径不再经过
  ResourceHttpRequestHandler,抛的是 NoHandlerFoundException,只处理
  NoResourceFoundException 时访问 / 会变成 500「系统繁忙」并刷 ERROR 日志

deploy
- 新增 xt-nginx(80):发 frontend-mp/dist/build/h5 + /api 反代 8080(host.docker.internal,
  Linux 靠 extra_hosts host-gateway),端口与产物目录走 .env 的 H5_PORT/H5_DIR
- 三条"删了就会出事"的都已带上理由:client_max_body_size 50m(默认 1m,超了回 413
  而后端日志一个字都没有)、/assets 的 immutable 与 *.html 的 no-cache(§一·十 那个
  "发版后学生看到旧页面"的坑)、健康检查写 127.0.0.1(容器里 localhost 先解析到 IPv6,
  nginx 只听 IPv4 → 永远 starting 而首页是好的)

CI 与文档
- CI:学生端 H5 构建从"e2e 的输入"改为编译检查,不再留 artifact(e2e 不消费它)
- 同步 AGENTS.md / README.md / docs/09(启动步骤、CI 表、发布注意、排障表)/ docs/11
- 交接摘要新增 §一·四十三(含理由、验证数字、要人工做的一步与环境限制)

验证
- mvn clean package 通过(必须 clean:删掉的旧类会留在 target/classes 被组件扫描)
- 后端直连:/ 与 /assets/* → 404({"code":40001,"msg":"接口不存在"})、
  /api/.../captcha → 200 + no-store、/doc.html → 302→200、/v3/api-docs 与 /actuator/health → 200
- 经 nginx(80):首页 200 + no-cache、/assets/*.js 200 + immutable、/nope.js 404(无回退)、
  /api 200 + no-store、gzip 生效;2MB multipart 上传 → 401(与直连一致 ⇒ 未踩 1m 的坑)、
  55MB → 413
- e2e(XT_BASE=http://localhost,全程走 nginx):e2e-m0.py 37/37、e2e-m3-h5-auth.py 24/24、
  e2e-m2-scope.py 38/38
- verify-all.py --quick 6/6;check-test-profile.py:test profile 仍能起来
2026-10-19 17:35:33 +08:00

60 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* API 地址。
*
* ⚠️ **H5 与小程序必须用不同的策略**,写死一个值一定会在某一边出错:
*
* · **H5**:与接口**同域**(H5 由 nginx 托管、`/api` 由同一个 nginx 反代到后端 8080,
* 见 deploy/nginx/xt.conf),所以用**相对路径(空串)**。这样:
* ① 完全不经过 CORS —— 换域名也不用改配置;
* ② 不会出现"手机能从 A 域名加载页面、却向后端 B 域名发请求"这种毛病。
* ⚠️ 曾经的写法是硬编码 `http://localhost:8080`,于是从公网域名打开时
* 变成了跨域请求 → 被 CORS 拦 → 页面显示"网络请求失败",
* 而**从本机打开却是好的**。这个 bug 只有走真实穿透/真机才会暴露。
*
* · **小程序**:没有"同域"这个概念,必须写绝对地址。
* 开发者工具里可以用 `http://localhost:8080`(需勾"不校验合法域名");
* 真机要用局域网 IP;正式版必须是 HTTPS + 已在小程序后台配好的域名。
*
* 用 uni-app 的条件编译区分两端,而不是运行期判断 —— 后者会把两套地址都打进包里。
*/
// #ifdef H5
/**
* H5:优先取 `VITE_API_BASE`,没有才用**同源的** `location.origin`。
*
* ⚠️ 为什么要有 `VITE_API_BASE` 这一档:
*
* `location.origin` 是"与页面同源",这在**由 nginx 托管构建产物**时是对的
* (`http://localhost` 上页面与接口同源;2026-10 之前是后端 8080 托管,现在那个端口只有 /api)。
* 但 `pnpm dev:h5` 起的是一个**独立的 vite dev server**(另一个端口)——
* 那时 `location.origin` 指的是 dev server 自己,接口就打到 dev server 上去了,
* 于是只能"build 一次再看",改一行要等一次完整构建。
*
* 所以 dev server 下把这个值设成**空串**(见 `.env.development`),
* 让请求走相对路径 `/api/...`,再由 vite 的 `server.proxy` 转发到后端。
*
* ⚠️ 另外:`uni.request` **不能**传相对路径(实测会 `request:fail`,
* 而同样地址用原生 XHR/fetch 是 200)。所以空串时补上 `location.origin`,
* 保持"绝对地址"这个前提不变 —— 只是那个 origin 由代理兜住。
*/
const VITE_API_BASE = (import.meta.env?.VITE_API_BASE ?? '') as string
export const API_BASE_URL =
VITE_API_BASE !== '' ? VITE_API_BASE
: (typeof location !== 'undefined' ? location.origin : '')
// #endif
// #ifndef H5
export const API_BASE_URL = 'http://localhost:8080'
// #endif
/** 主题色(与 PC 管理端同一套腾讯云 TDesign 色板,两端视觉要一致)。 */
export const THEME = {
primary: '#0052D9',
success: '#00A870',
warning: '#ED7B2F',
danger: '#E34D59',
pageBg: '#F3F3F3',
textPrimary: '#000000E6',
textSecondary: '#00000099',
textPlaceholder: '#0000004D'
} as const