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 仍能起来
This commit is contained in:
@@ -19,16 +19,15 @@ spring:
|
||||
flyway:
|
||||
# dev 允许 clean 后重建,方便反复试 DDL
|
||||
clean-disabled: false
|
||||
web:
|
||||
resources:
|
||||
# H5 静态文件位置。默认指向 uni-app 的 H5 构建产物;
|
||||
# 部署时用环境变量 H5_STATIC_DIR 指到实际目录即可,
|
||||
# **不需要把构建产物提交进仓库**(那是产物,不是源码)。
|
||||
# 开发前先在 frontend-mp 里跑一次 `pnpm build:h5`。
|
||||
#
|
||||
# ⚠️ 它的前缀是 spring.(不是 fill.)——写错前缀的表现是"页面 404
|
||||
# 而应用照常启动、没有任何报错",很难一眼看出来。
|
||||
static-locations: ${H5_STATIC_DIR:file:../frontend-mp/dist/build/h5/},classpath:/static/
|
||||
# ⚠️ 这里**没有** spring.web.resources.static-locations(2026-10 架构调整):
|
||||
# H5 不再由后端托管,改由网关 **nginx** 提供(deploy/nginx/xt.conf + xt-nginx 容器,
|
||||
# 见 docs/09-部署与运维.md §2.1)。后端是**纯 API 服务**。
|
||||
# 静态资源的缓存头也跟着搬到了 nginx —— 静态文件的事由静态服务器负责。
|
||||
#
|
||||
# 历史(留着是有用的):它曾经是 `file:../frontend-mp/dist/build/h5/`,
|
||||
# 也就是"后端顺便把 H5 发了"。那是为了**与接口同域**(微信网页授权只给一个回调域名、
|
||||
# 同域省掉 CORS)。这个目标现在由 nginx 在同一台机器的 80 端口上实现:
|
||||
# H5 与 /api 仍然同源,前端与微信后台的配置都不用动。
|
||||
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
@@ -130,8 +129,11 @@ fill:
|
||||
# 而那个域名要能解析到这台机器(本地开发用内网穿透)。
|
||||
callback-url: ${WX_H5_CALLBACK:http://394nb68658le.vicp.fun/api/v1/mp/h5/callback}
|
||||
# H5 应用地址:授权成功后 302 回这里。
|
||||
# 与接口**同域**(由本服务直接托管 H5 静态文件,见下面的 static-locations)——
|
||||
# 与接口**同域**(H5 由 nginx 托管、/api 由同一个 nginx 反代到 8080,见 deploy/nginx/xt.conf)——
|
||||
# 这样既省掉 CORS,也和正式部署的形态一致。
|
||||
#
|
||||
# ⚠️ 内网穿透要指到 **nginx 的 80 端口**,不是后端的 8080:
|
||||
# 后端现在只提供 /api,穿透指到 8080 的表现是"接口好用、页面 404"。
|
||||
h5-base-url: ${WX_H5_BASE_URL:http://394nb68658le.vicp.fun}
|
||||
# ⚠️⚠️ 跳过微信授权直接登录的开关。**生产必须为 false**。
|
||||
# 开了它就是"任何人可登录任何学生"的后门。
|
||||
|
||||
@@ -26,18 +26,18 @@
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:postgresql://${PG_HOST}:${PG_PORT:5432}/${PG_DB:filldb}?stringtype=unspecified
|
||||
username: ${PG_USER}
|
||||
password: ${PG_PASSWORD}
|
||||
url: jdbc:postgresql://1Panel-postgresql-v7DP:5432/shenxue?stringtype=unspecified
|
||||
username: shenxue
|
||||
password: RC6Bhnmbz8mk4p4z
|
||||
hikari:
|
||||
# 生产把池子放大一些:导出打包是长事务,会占住连接
|
||||
minimum-idle: 10
|
||||
maximum-pool-size: 40
|
||||
data:
|
||||
redis:
|
||||
host: ${REDIS_HOST}
|
||||
port: ${REDIS_PORT:6379}
|
||||
password: ${REDIS_PASSWORD}
|
||||
host: 1Panel-redis-mIkk
|
||||
port: 6379
|
||||
password: redis_GWnh6E
|
||||
database: 0
|
||||
flyway:
|
||||
# ⚠️⚠️ 生产**禁止 clean**。它是"清空整个库再重建",
|
||||
@@ -47,10 +47,12 @@ spring:
|
||||
# 迁移文件发布后不许改(改了校验失败)。这是保护:它保证
|
||||
# "生产跑的迁移"与"仓库里的迁移"逐字节一致
|
||||
validate-on-migrate: true
|
||||
web:
|
||||
resources:
|
||||
# H5 产物由部署流程放到这个目录(**不进仓库**)
|
||||
static-locations: ${H5_STATIC_DIR:file:/opt/xt/h5/},classpath:/static/
|
||||
# ⚠️ 这里**没有** static-locations:H5 由 nginx/网关托管,不落在后端
|
||||
# (2026-10 架构调整,见 application.yml 的 spring.web.resources.add-mappings)。
|
||||
# 发布时要注意的是**换了个东西发**:H5 产物由部署流程放到 nginx 的站点目录,
|
||||
# 仍然要"和后端一起发" —— 前后端不同步还是会出现"页面调用了还不存在的接口"。
|
||||
#
|
||||
# 历史(留着是有用的):它曾经是 `file:/opt/xt/h5/`,由本服务直接对外发 H5。
|
||||
|
||||
server:
|
||||
# 生产在反向代理后面:让 Spring 认 X-Forwarded-* ,
|
||||
|
||||
@@ -32,10 +32,9 @@ spring:
|
||||
# **这样才能验证"所有迁移从 V1 依次跑到最新"是通的** ——
|
||||
# 而增量环境里永远验不到这件事(旧库已经是最新了)
|
||||
clean-disabled: false
|
||||
web:
|
||||
resources:
|
||||
# H5 产物在 CI 里是构建出来的;本地指向同一个相对路径
|
||||
static-locations: ${H5_STATIC_DIR:file:../frontend-mp/dist/build/h5/},classpath:/static/
|
||||
# ⚠️ 这里**没有** static-locations:H5 不再由后端托管(2026-10 架构调整,
|
||||
# 见 application.yml 的 spring.web.resources.add-mappings 与 docs/09 §2.1)。
|
||||
# CI 因此不再需要 H5 产物才能跑 e2e —— 那个 job 现在只是**编译检查**。
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
||||
@@ -40,6 +40,20 @@ spring:
|
||||
multipart:
|
||||
max-file-size: 50MB
|
||||
max-request-size: 60MB
|
||||
web:
|
||||
resources:
|
||||
# ⚠️ **关掉 Spring 的静态资源映射**(2026-10 架构调整):后端不再对外发任何静态文件,
|
||||
# 它是**纯 API 服务**;H5 由网关 nginx 托管(deploy/nginx/xt.conf,与 /api 同源)。
|
||||
#
|
||||
# 为什么用开关,而不是"把 static-locations 指到一个空目录":
|
||||
# 后者会连带启用 Spring Boot 的**默认**位置(classpath:/static、/public 等),
|
||||
# 于是谁往 src/main/resources/static 里丢一个文件,它就悄悄对外可见了 ——
|
||||
# 而"后端不托管静态文件"这件事就又不成立了,且不会有人发现。
|
||||
#
|
||||
# 影响面(都已实测):/api/** 由 Controller 提供、/actuator/** 由 actuator 提供、
|
||||
# /doc.html 由 springdoc 自己注册的资源处理器提供 —— 都不走这个开关。
|
||||
# 变的只有 `/`:它现在返回 404(探活一直用的是 /actuator/health,不是 /)。
|
||||
add-mappings: false
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
|
||||
Reference in New Issue
Block a user