fix(config): 本地私有配置改用 profile 机制(spring.config.import 优先级不够)

起因:用户把七牛 AK/SK 填进了 application-dev.yml(**会提交的文件**)。
已把密钥挪到 jar 外的 backend/application-local.yml(gitignore),
并把 dev 文件还原成空占位符 —— 确认过待提交差异里没有密钥。

⚠️ 排查中发现一个**沉默的坑**:一开始用
  spring.config.import: optional:file:./application-local.yml
加载本地密钥,结果**启动正常、日志不报错、但配的 provider 完全没生效**
(还是本地磁盘)。三步定位:
  ① 确认 YAML 合法(结构/编码/缩进都对)→ 不是文件问题
  ② 换 --spring.config.additional-location=file:./... → **生效了**
     → 文件与内容没问题,问题在 import 这条路
  ③ 把 import 改成**非可选 + 指向不存在的文件** → 启动失败并报
     "Config data resource ... does not exist"
     → 证明 import **确实被处理了**,是**优先级**问题

根因:spring.config.import 导入的文件排在 **profile 文件之后(优先级更低)**,
于是 application-dev.yml 里的 storage.provider 把导入文件里的 provider: qiniu
盖掉了 —— 而这一切没有任何报错。

修法:改用标准机制 —— 文件恢复成 profile 名 application-local.yml,
application.yml 里加 spring.profiles.include: local。
profile 文件后加载、优先级更高。启动日志现在打印
  The following 2 profiles are active: "local", "dev"
那个坑已写进 application.yml 的注释里,免得后人再踩。

教训:**"配置了但没生效、且不报错"是最难查的一类问题。**
判断某个配置机制到底有没有被执行,有个通用办法:
**把它改成一个必然会失败的值** —— 如果照样跑起来,说明它根本没被处理。

⛔ 仍阻塞:用户填的 AK/SK **验证无效**(七牛 401 bad token)。
两个互相独立的签名实现都失败,所以不是代码问题:
  ① 七牛官方 SDK 的 Auth.uploadToken(自检走的就是它)
  ② 手写的管理 API 签名(GET https://rs.qiniu.com/buckets)
线索:AK 40 字符正常、**SK 41 字符**(七牛的 AK/SK 都是 40 字符的 URL 安全 base64);
但逐字符试"去掉首/尾字符"三种组合都被拒 → 不是收尾多一个字符。
需要用户到七牛控制台 → 密钥管理重新完整复制一对。

为不阻塞本地开发,application-local.yml 里 provider 先留 local(密钥保留着,
换成有效的之后去掉一行注释即可)。回归:e2e-m3-file 29/29、m3-submit 31/31。
This commit is contained in:
2026-09-29 14:38:37 +08:00
parent 65ebf8de90
commit b9373d6ebd
3 changed files with 79 additions and 7 deletions
@@ -19,14 +19,15 @@ spring:
name: xt-server
profiles:
active: dev
config:
# 本地私有配置(**不提交**):放云存储密钥这类不该进仓库的东西。
# optional: 没有这个文件也能正常启动(默认值都在各自的 yml 里)。
# 额外挂一个 local 配置(backend/application-local.yml,**不提交**)。
# 用它放云存储密钥这类不该进仓库的东西;文件不存在时是空操作,不影响任何环境。
#
# ⚠️ 刻意用 file: 前缀(而不是 classpath:)—— 放 classpath 里会被**打进 jar**,
# 密钥就跟着构建产物到处走了。放在 jar 外面才能保证"构建产物里没有密钥"。
# 模板见 backend/application-local.yml.example(那个是提交的)。
import: optional:file:./application-local.yml
# ⚠️ 为什么不用 spring.config.import —— 试过,**优先级不够**:
# 导入的文件排在 profile 文件之后(优先级更低),于是
# application-dev.yml 里的 provider 会把它盖掉,表现是
# "文件明明配了 qiniu,启动后却还是本地磁盘",而且不会有任何报错。
# profile 文件是后加载的,优先级更高,行为符合直觉。
include: local
lifecycle:
# 优雅停机:等在途请求处理完,避免上传/导出被打断
timeout-per-shutdown-phase: 30s