feat(#1718): 微信 state Redis 化 + 回调 UA 日志 + 中文昵称 UTF-8 修复 #1724

Merged
xiaoxia merged 1 commits from feature/wechat-state-redis-1718 into develop 2026-09-05 21:03:17 +08:00
Owner

改动

1. state 存储 Redis 化(多实例/容器重启安全)

  • 新增 RedisStateStore:复用 celery Redis,key 前缀 wechat:state:,TTL 10 分钟
  • SET NX EX 写入;Lua 脚本原子 GET+DEL 一次性消费(兼容 Redis <6.2 无 GETDEL),eval 不可用退化 GET+DELETE
  • Redis 不可用时自动降级 MemoryStateStore,登录流程不中断
  • get_wechat_oauth_service() 单例默认使用 Redis store(取 CELERY_BROKER_URL/REDIS_URL),配置缺失降级内存

2. /wechat/callback 可观测日志

  • 记录 User-Agent(识别 MicroMessenger 微信内置浏览器)、state 校验结果、失败上下文
  • 便于排查「停留 open.weixin.qq.com / 回调失败」类问题

3. 中文昵称乱码修复

  • sns/oauth2/access_token 与 sns/userinfo 响应在 .json() 前显式 encoding=utf-8
  • 微信响应头不带 charset,requests 默认按 ISO-8859-1 解码导致中文昵称乱码

测试

  • 15 个新单测(全 mock/fake,CI 无真实 redis 也产生覆盖):Redis state 存取/一次性消费/Lua 与 eval 降级/异常降级内存/ping 失败降级、中文昵称 UTF-8 解析、errcode 透传、callback 路由成功与失败日志分支、工厂配置降级分支
  • 全量 14358 passed(5 个失败为已知 h2 TTS 沙箱问题),black/isort/ruff/mypy 通过,diff coverage 100%

OSS 直传排查结论(另见群里汇报)

OSS bucket CORS 规则、presign 有效期、endpoint/区域均正常(实测签名 POST 201 成功);1GB 上传失败时后端 72h 无任何 prepare 请求到达,问题在前端 prepare 之前阶段(整文件哈希阻塞/默认项目创建),属前端 #1718/#1714 任务范围。

## 改动 ### 1. state 存储 Redis 化(多实例/容器重启安全) - 新增 `RedisStateStore`:复用 celery Redis,key 前缀 `wechat:state:`,TTL 10 分钟 - `SET NX EX` 写入;Lua 脚本原子 `GET+DEL` 一次性消费(兼容 Redis <6.2 无 GETDEL),eval 不可用退化 GET+DELETE - Redis 不可用时自动降级 `MemoryStateStore`,登录流程不中断 - `get_wechat_oauth_service()` 单例默认使用 Redis store(取 CELERY_BROKER_URL/REDIS_URL),配置缺失降级内存 ### 2. /wechat/callback 可观测日志 - 记录 User-Agent(识别 MicroMessenger 微信内置浏览器)、state 校验结果、失败上下文 - 便于排查「停留 open.weixin.qq.com / 回调失败」类问题 ### 3. 中文昵称乱码修复 - sns/oauth2/access_token 与 sns/userinfo 响应在 `.json()` 前显式 `encoding=utf-8` - 微信响应头不带 charset,requests 默认按 ISO-8859-1 解码导致中文昵称乱码 ### 测试 - 15 个新单测(全 mock/fake,CI 无真实 redis 也产生覆盖):Redis state 存取/一次性消费/Lua 与 eval 降级/异常降级内存/ping 失败降级、中文昵称 UTF-8 解析、errcode 透传、callback 路由成功与失败日志分支、工厂配置降级分支 - 全量 14358 passed(5 个失败为已知 h2 TTS 沙箱问题),black/isort/ruff/mypy 通过,diff coverage 100% ## OSS 直传排查结论(另见群里汇报) OSS bucket CORS 规则、presign 有效期、endpoint/区域均正常(实测签名 POST 201 成功);1GB 上传失败时后端 72h 无任何 prepare 请求到达,问题在前端 prepare 之前阶段(整文件哈希阻塞/默认项目创建),属前端 #1718/#1714 任务范围。
xiaoxia added 1 commit 2026-09-05 20:45:24 +08:00
feat(#1718): 微信 state 存储 Redis 化 + 回调 UA 日志 + 中文昵称 UTF-8 修复
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 26s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 25s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m42s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 1m47s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 2m6s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m16s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m55s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 3m2s
AI Code Review / AI Code Review (pull_request) Successful in 3m53s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 10m31s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 15m42s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 8s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 1m14s
f11b71361d
- state store 改 Redis(复用 celery Redis,key 前缀 wechat:state:,
  TTL 10 分钟):SET NX EX 写入,Lua 脚本原子 GET+DEL 一次性消费
  (兼容 Redis <6.2 无 GETDEL);Redis 不可用时自动降级内存,登录不中断;
  容器重启/多实例后 state 不丢,修复 worker 扩容后回调 state 失效
- /wechat/callback 加可观测日志:User-Agent(识别 MicroMessenger
  微信内置浏览器)、state 校验结果、失败上下文,便于排查回调停滞
- 修复微信中文昵称乱码:sns/oauth2/access_token 与 sns/userinfo
  响应在 .json() 前显式 encoding=utf-8(微信响应头不带 charset,
  requests 默认 ISO-8859-1 解码导致中文乱码)
- 15 个新单测(全 mock/fake,CI 无 redis 也覆盖):Redis state
  存取/一次性消费/eval 降级/异常降级内存/ping 失败降级、中文昵称
  UTF-8 解析、errcode 透传、callback 路由日志分支、工厂降级分支

🚀 预览环境已部署

项目 详情
PR号 #1724
预览链接 https://pr-1724.preview.xiaoxiajianji.com
API环境 staging

💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。

🔄 每次提交新代码后预览环境会自动更新。

🗑️ PR 关闭或合并后,预览环境会自动清理。

🚀 **预览环境已部署** | 项目 | 详情 | |------|------| | PR号 | #1724 | | 预览链接 | [https://pr-1724.preview.xiaoxiajianji.com](https://pr-1724.preview.xiaoxiajianji.com) | | API环境 | staging | > 💡 预览环境使用 staging API 数据,请勿在预览环境中操作重要数据。 > > 🔄 每次提交新代码后预览环境会自动更新。 > > 🗑️ PR 关闭或合并后,预览环境会自动清理。
Collaborator

【阻塞级判定】

  • 是否存在阻塞级问题:否
  • 阻塞级问题数量:0 个

📊 审查概览

  • 整体评价:通过
  • 建议级问题数量:2 个

🔴 阻塞级问题(必须修复)

💡 改进建议(不阻塞合并)

  1. [wechat_oauth_service.py: 73] RedisStateStore.put 方法建议检查返回值

    • 具体内容:self._redis.set(..., nx=True, ...) 在 key 已存在时会返回 False。虽然 state 碰撞概率极低,但若发生碰撞会导致 state 未成功写入 Redis,进而导致后续回调验证失败。建议增加对返回值的判断,若为 False 可记录警告日志或抛出异常,以便于排查极端情况下的登录失败问题。
  2. [wechat_oauth_service.py: 288] _build_default_state_store 函数建议增加日志

    • 具体内容:在函数决定使用 Redis 还是 Memory 存储时,建议增加一条 Info 级别的日志,明确记录当前使用的 State Store 类型(Redis 或 Memory),有助于运维人员在部署时快速确认配置是否生效。

良好实践

  • 优雅降级策略RedisStateStore 在 Redis 不可用时自动降级到 MemoryStateStore,并在写入/读取异常时尝试降级,保证了服务的高可用性。
  • 原子性操作:使用 Lua 脚本保证 state 的读取与删除操作的原子性,防止并发竞争条件。
  • 编码修复:显式设置 resp.encoding = "utf-8" 修复了微信 API 返回中文乱码的问题,定位准确。
  • 可观测性增强:在回调接口中增加了详细的日志记录(UA、state、错误信息),极大提升了线上问题的排查效率。

格式检查通过 | 逻辑审查通过 | 性能良好


🤖 由 AI 代码审查机器人自动生成 | 2026-09-05 12:49:18 | 模型:

### 【阻塞级判定】 - 是否存在阻塞级问题:否 - 阻塞级问题数量:0 个 ### 📊 审查概览 - 整体评价:通过 - 建议级问题数量:2 个 ### 🔴 阻塞级问题(必须修复) 无 ### 💡 改进建议(不阻塞合并) 1. **[wechat_oauth_service.py: 73] RedisStateStore.put 方法建议检查返回值** - 具体内容:`self._redis.set(..., nx=True, ...)` 在 key 已存在时会返回 `False`。虽然 state 碰撞概率极低,但若发生碰撞会导致 state 未成功写入 Redis,进而导致后续回调验证失败。建议增加对返回值的判断,若为 `False` 可记录警告日志或抛出异常,以便于排查极端情况下的登录失败问题。 2. **[wechat_oauth_service.py: 288] _build_default_state_store 函数建议增加日志** - 具体内容:在函数决定使用 Redis 还是 Memory 存储时,建议增加一条 Info 级别的日志,明确记录当前使用的 State Store 类型(Redis 或 Memory),有助于运维人员在部署时快速确认配置是否生效。 ### ✅ 良好实践 - **优雅降级策略**:`RedisStateStore` 在 Redis 不可用时自动降级到 `MemoryStateStore`,并在写入/读取异常时尝试降级,保证了服务的高可用性。 - **原子性操作**:使用 Lua 脚本保证 state 的读取与删除操作的原子性,防止并发竞争条件。 - **编码修复**:显式设置 `resp.encoding = "utf-8"` 修复了微信 API 返回中文乱码的问题,定位准确。 - **可观测性增强**:在回调接口中增加了详细的日志记录(UA、state、错误信息),极大提升了线上问题的排查效率。 --- ✅ 格式检查通过 | ✅ 逻辑审查通过 | ✅ 性能良好 --- <sub>🤖 由 AI 代码审查机器人自动生成 | 2026-09-05 12:49:18 | 模型: </sub> <!-- AI_CODE_REVIEW_AUTO_COMMENT -->
xiaoxia merged commit 5575d98512 into develop 2026-09-05 21:03:17 +08:00

🗑️ 预览环境已清理

PR #1724 已关闭或合并,对应的预览环境已被清理。

如有需要,可以重新打开 PR 来重新生成预览环境。

🗑️ **预览环境已清理** PR #1724 已关闭或合并,对应的预览环境已被清理。 > 如有需要,可以重新打开 PR 来重新生成预览环境。
Sign in to join this conversation.