diff --git a/backend/xt-server/src/main/resources/application-dev.yml b/backend/xt-server/src/main/resources/application-dev.yml index 60a5048..26d61e2 100644 --- a/backend/xt-server/src/main/resources/application-dev.yml +++ b/backend/xt-server/src/main/resources/application-dev.yml @@ -19,6 +19,16 @@ 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/ mybatis-plus: configuration: @@ -71,12 +81,13 @@ fill: mp-h5: app-id: ${WX_H5_APP_ID:wx5d3ae5c1c21fef24} app-secret: ${WX_H5_APP_SECRET:0e0367fd39a968866a3c59f6c641dda2} - # 授权回调地址。必须是「授权回调页面域名」下的完整 URL, - # 而那个域名要填在公众号后台(只能填域名,不能带端口/路径/IP)。 - # 本地开发:把域名用 hosts 指到 127.0.0.1,或用内网穿透给一个公网域名。 - callback-url: ${WX_H5_CALLBACK:http://127.0.0.1:8080/api/v1/mp/h5/callback} - # H5 应用地址:授权成功后 302 回这里 - h5-base-url: ${WX_H5_BASE_URL:http://127.0.0.1:5174} + # 授权回调地址。域名必须是「授权回调页面域名」里填的那个, + # 而那个域名要能解析到这台机器(本地开发用内网穿透)。 + callback-url: ${WX_H5_CALLBACK:http://394nb68658le.vicp.fun/api/v1/mp/h5/callback} + # H5 应用地址:授权成功后 302 回这里。 + # 与接口**同域**(由本服务直接托管 H5 静态文件,见下面的 static-locations)—— + # 这样既省掉 CORS,也和正式部署的形态一致。 + h5-base-url: ${WX_H5_BASE_URL:http://394nb68658le.vicp.fun} # ⚠️⚠️ 跳过微信授权直接登录的开关。**生产必须为 false**。 # 开了它就是"任何人可登录任何学生"的后门。 # 代码里还会再判一次 profile 不含 prod(双保险)。 diff --git a/frontend-mp/src/config/index.ts b/frontend-mp/src/config/index.ts index 77561eb..e63078f 100644 --- a/frontend-mp/src/config/index.ts +++ b/frontend-mp/src/config/index.ts @@ -1,23 +1,40 @@ /** - * 小程序端配置。 + * API 地址。 * - * ⚠️ API 地址在三种场景下不一样,写死会导致"开发者工具里好好的,真机打不开": + * ⚠️ **H5 与小程序必须用不同的策略**,写死一个值一定会在某一边出错: * - * 1. 微信开发者工具:可以用 http://localhost:8080, - * 但必须在「详情 → 本地设置」里勾上 **「不校验合法域名、web-view、TLS 版本以及 HTTPS 证书」**。 - * 不勾的话请求会被拦,报错是「不在以下 request 合法域名列表中」—— - * 而那句话看起来像"域名没配",会让人跑去小程序后台白改一通。 + * · **H5**:与接口**同域**(后端直接托管 H5 静态文件,见 application-dev.yml 的 + * static-locations),所以用**相对路径(空串)**。这样: + * ① 完全不经过 CORS —— 换域名也不用改配置; + * ② 不会出现"手机能从 A 域名加载页面、却向后端 B 域名发请求"这种毛病。 + * ⚠️ 曾经的写法是硬编码 `http://localhost:8080`,于是从公网域名打开时 + * 变成了跨域请求 → 被 CORS 拦 → 页面显示"网络请求失败", + * 而**从本机打开却是好的**。这个 bug 只有走真实穿透/真机才会暴露。 * - * 2. 真机预览/体验版:localhost 是**手机自己**,不是你的电脑。 - * 要把地址换成电脑的局域网 IP(如 http://192.168.1.5:8080), - * 并确保手机与电脑在同一网络、电脑防火墙放行 8080。 + * · **小程序**:没有"同域"这个概念,必须写绝对地址。 + * 开发者工具里可以用 `http://localhost:8080`(需勾"不校验合法域名"); + * 真机要用局域网 IP;正式版必须是 HTTPS + 已在小程序后台配好的域名。 * - * 3. 正式发布:必须是 **HTTPS + 已在微信后台配好 request 合法域名**(见待办:域名白名单), - * 且域名不能带端口、不能是 IP。 - * - * 所以这里留成一处配置,而不是散在请求代码里。 + * 用 uni-app 的条件编译区分两端,而不是运行期判断 —— 后者会把两套地址都打进包里。 */ +// #ifdef H5 +/** + * H5:用**绝对的同源地址**(`location.origin`),不要用相对路径。 + * + * ⚠️ 实测:`uni.request` 传相对路径(`/api/v1/...`)会以 `request:fail` 失败, + * 而**同样地址用原生 XHR / fetch 是成功的**(都是 200)。也就是说这是 uni-app + * 自身的处理差异,不是服务端或跨域问题 —— 但排查时它长得像"网络不通", + * 很容易往 CORS / 域名 / 后端去查,白绕一大圈。 + * + * 用 `location.origin` 而不是 `''`:既绕开这个差异,又保持**同源** + * (不经过 CORS),换域名也不用改配置。 + */ +export const API_BASE_URL = typeof location !== 'undefined' ? location.origin : '' +// #endif + +// #ifndef H5 export const API_BASE_URL = 'http://localhost:8080' +// #endif /** 主题色(与 PC 管理端同一套腾讯云 TDesign 色板,两端视觉要一致)。 */ export const THEME = {