一、整体架构
方案 A:直连模式(默认)
方案 B:反向代理模式(推荐)
核心原则:前端不直接调用微信 API,所有微信接口调用都通过 Supabase Edge Functions 代理,避免在客户端暴露AppSecret。用户可以选择直连模式或反向代理模式解决 IP 白名单问题。
二、前置准备
2.1 微信开发者平台后台配置
在 微信开发者平台 完成以下操作:-
获取开发者凭证
- 访问 微信开发者平台
- 选择对应的公众号
- 在「基础信息」中查看或重置
- 记录
AppID(开发者 ID) - 记录或重置
AppSecret(开发密钥)
-
配置 IP 白名单
- 在「基础信息 → 开发密钥 → API IP白名单」中添加 Edge Function 的出口 IP
- ⚠️ 重要:Supabase Edge Functions 使用动态 IP,首次调用会返回
errcode: 40164,从错误信息中提取 IP 并添加到白名单 - 提取方式:解析
errmsg中的invalid ip x.x.x.x
-
确认公众号类型
- 已认证的服务号拥有全部接口权限
- 订阅号部分接口受限(如自定义菜单、数据统计)
2.2 Supabase 项目配置
-
环境变量 / Edge Function Secrets
需要配置以下 Secrets(通过 Supabase Dashboard 或 CLI):
Secret 名称 说明 示例 SUPERUN_WECHAT_APP_ID公众号 AppID wx1234567890abcdefSUPERUN_WECHAT_APP_SECRET公众号 AppSecret a1b2c3d4e5f6...SUPERUN_WECHAT_API_PROXY_URL反向代理地址(可选) https://wechat-proxy.example.comSUPABASE_URLSupabase 项目 URL(内置) https://xxxxx.supabase.coSUPABASE_ANON_KEYSupabase 匿名密钥(内置) eyJhbG...SUPABASE_SERVICE_ROLE_KEYSupabase 服务角色密钥(内置) eyJhbG...其中
SUPABASE_URL、SUPABASE_ANON_KEY、SUPABASE_SERVICE_ROLE_KEY是 Supabase 内置的,无需手动配置。SUPERUN_WECHAT_API_PROXY_URL为可选项,不配置则直连微信 API(需手动维护 IP 白名单),配置后所有微信请求走代理服务器。 -
Edge Function 配置(
supabase/config.toml)verify_jwt = false允许 Edge Function 之间互相调用。认证逻辑在函数内部通过解析 JWT 手动实现。
三、数据库表结构
3.1 wechat_tokens — 令牌缓存表
3.2 articles — 图文内容表
3.3 menu_configs — 菜单配置表
3.4 auto_reply_rules — 自动回复规则表
四、Edge Functions 详解
4.1 wechat-token — 令牌管理服务
职责:获取并缓存微信 access_token,所有其他 Edge Function 通过调用此服务获取令牌。
请求方式:GET 或 POST
核心逻辑:
4.2 wechat-data — 数据统计服务
职责:代理微信数据统计接口(datacube)和粉丝 / 菜单查询。
请求方式:POST
TokenResult 模式(所有需要 access_token 的函数统一使用):
关键设计:当令牌获取失败(如 IP 被封)时,不抛异常,而是返回 { blocked_ip } 给前端,让前端展示友好提示。
支持的 action:
| action | 微信 API | 说明 | 日期限制 |
|---|---|---|---|
get-menu | GET /cgi-bin/menu/get | 获取当前菜单 | 无 |
get-follower-count | GET /cgi-bin/user/get | 获取粉丝总数 | 无 |
user-summary | POST /datacube/getusersummary | 用户增减数据 | 最多 7 天 |
user-cumulate | POST /datacube/getusercumulate | 累计用户数据 | 最多 7 天 |
article-summary | POST /datacube/getarticlesummary | 图文群发日数据 | 最多 1 天 |
article-total | POST /datacube/getarticletotal | 图文群发总数据 | 最多 1 天 |
upstream-msg | POST /datacube/getupstreammsg | 消息概况 | 最多 7 天 |
interface-summary | POST /datacube/getinterfacesummary | 接口分析 | 最多 30 天 |
4.3 wechat-articles — 图文管理服务
职责:图文 CRUD、发布到微信、从微信同步已发布文章。
支持的 action:
| action | 说明 | 需要认证 |
|---|---|---|
save-draft | 保存 / 更新草稿 | ✅ |
publish | 发布到微信(草稿 → 群发) | ✅ |
delete | 软删除文章 | ✅ |
sync-published | 从微信同步已发布文章 | ✅ |
4.4 wechat-menu — 自定义菜单服务
职责:将本地菜单配置同步到微信、清空微信菜单。
支持的 action:
| action | 说明 | 参数 |
|---|---|---|
publish | 发布菜单到微信 | menu_config_id (必填) |
delete | 清空微信菜单 | menu_config_id (可选) |
publish 时发现菜单为空(button.length === 0),自动调用 delete 接口清空微信菜单,而非创建一个空菜单。
菜单数据结构(微信标准格式):
五、前端集成模式
5.1 统一的 Hook 封装
所有微信 API 调用都封装为 React Query hooks:5.2 IP 白名单错误处理(通用模式)
所有与微信交互的页面都实现了统一的 IP 白名单错误处理:5.3 手动同步(连通性检查)
六、关键注意事项
6.1 IP 白名单问题 — 两种解决方案
Supabase Edge Functions 使用动态出口 IP,无法预先配置白名单。用户可根据自身情况选择以下任一方案:方案 A:IP 白名单(手动维护)
适合场景:快速验证、临时使用、没有服务器资源。 步骤:- 首次调用微信 API 会返回
errcode: 40164 - 从
errmsg中提取被拒绝的 IP:invalid ip x.x.x.x - 将该 IP 添加到公众号白名单
- 应用前端会展示橙色提示条,支持一键复制 IP
- Edge Function IP 可能会变动,需要重新添加
- 需要手动操作微信后台
方案 B:反向代理(推荐,一劳永逸)
适合场景:生产环境、长期使用、不想每次 IP 变动都手动加白名单。 原理:在一台有固定公网 IP 的服务器上部署 Nginx 反向代理,所有微信 API 请求都经过这台服务器转发。微信只看到代理服务器的固定 IP,加一次白名单就永久生效。 步骤 1:部署代理服务器 准备一台有固定公网 IP 的服务器(云服务器即可,最低配置就行),安装 Nginx,配置如下:也可以用 HTTP(端口 80),但建议使用 HTTPS 保证传输安全。步骤 2:配置微信 IP 白名单 将代理服务器的固定公网 IP 添加到微信开发者平台「基础信息 → 开发密钥 → API IP白名单」。 步骤 3:配置 Edge Function Secret 在 Supabase 后台添加 Edge Function Secret:
| Secret 名称 | 值 | 示例 |
|---|---|---|
SUPERUN_WECHAT_API_PROXY_URL | 代理服务器地址 | https://wechat-proxy.your-domain.com |
注意:地址末尾不要加 /。
步骤 4:验证
配置完成后重新部署 Edge Functions,调用任意微信接口验证连通性。
代码层面的实现:
所有 Edge Function 均通过以下一行代码自动切换直连 / 代理模式:
- 未配置
SUPERUN_WECHAT_API_PROXY_URL→ 直连api.weixin.qq.com(方案 A) - 已配置 → 所有请求走代理地址(方案 B)
wechat-token(1 处)wechat-data(8 处)wechat-articles(3 处)wechat-menu(3 处)
- 从方案 A 切到方案 B:添加
SUPERUN_WECHAT_API_PROXY_URLSecret 并重新部署 - 从方案 B 切回方案 A:删除该 Secret 并重新部署
- 切换无需修改任何代码
两种方案对比
| 方案 A:IP 白名单 | 方案 B:反向代理 | |
|---|---|---|
| 配置难度 | 无需额外服务器 | 需要一台云服务器 + 域名 |
| 维护成本 | IP 变动时需手动更新 | 配置一次后无需维护 |
| 稳定性 | 依赖 Edge Function IP 不变 | 始终稳定 |
| 适合场景 | 开发测试、临时使用 | 生产环境、长期运行 |
| 切换方式 | 默认 | 添加/删除 Secret 即可 |
6.2 Access Token 管理
- 微信 access_token 有效期 2 小时,每日调用次数有限
- 通过
wechat_tokens表缓存,提前 5 分钟刷新 - 所有 Edge Function 都通过调用
wechat-token函数获取令牌,避免重复请求 - 定期清理过期令牌记录
6.3 微信 API 常见 errcode
| errcode | 含义 | 处理方式 |
|---|---|---|
40001 | access_token 无效 | 清除缓存重新获取 |
40164 | IP 不在白名单 | 提取 IP 提示用户添加 |
42001 | access_token 过期 | 自动刷新 |
46003 | 菜单不存在 | 正常情况,返回空菜单 |
61501 | 日期范围超限 | 检查日期区间是否超过 API 限制 |
45047 | 超出发布频率限制 | 提示用户稍后重试 |
6.4 数据统计日期限制
- 微信数据有 1 天延迟,
end_date最早只能是昨天 getusersummary/getusercumulate:最大跨度 7 天(含首尾)getarticlesummary/getarticletotal:最大跨度 1 天getupstreammsg:最大跨度 7 天getinterfacesummary:最大跨度 30 天- 日期格式:
YYYY-MM-DD
6.5 freepublish/batchget 字段注意
- 该接口返回的每条记录中,标识字段名为
article_id,不是media_id media_id是草稿箱接口(draft/add)返回的字段- 混淆这两个字段会导致同步时所有值为
undefined,数据无法写入
6.6 Edge Function 间调用
wechat-data、wechat-articles、wechat-menu都通过 HTTP 调用wechat-token- 调用时使用
SUPABASE_ANON_KEY或SUPABASE_SERVICE_ROLE_KEY做 Bearer Token config.toml中设置verify_jwt = false以允许跨函数调用
6.7 错误返回策略
所有涉及微信 API 的 Edge Function 统一遵循:- 令牌获取失败 + IP 被封:返回 HTTP
200+{ blocked_ip: "x.x.x.x" }- 返回 200 是为了让前端
supabase.functions.invoke()能正确读取data(非 200 会被放入error)
- 返回 200 是为了让前端
- 微信 API 业务错误:返回 HTTP
200+{ error: "...", errcode: xxx } - 系统错误:返回 HTTP
500+{ error: "..." }
七、部署清单
第一次部署前检查
通用步骤(两种方案都需要):- 微信开发者平台已获取
AppID和AppSecret - Supabase Edge Function Secrets 已配置
SUPERUN_WECHAT_APP_ID和SUPERUN_WECHAT_APP_SECRET - 数据库已创建
wechat_tokens、articles、menu_configs、auto_reply_rules表 -
supabase/config.toml中所有微信相关函数已设置verify_jwt = false
- 部署后首次调用,从错误响应中获取 Edge Function 出口 IP
- 将出口 IP 添加到微信开发者平台 IP 白名单
- 再次调用验证连通性
- 部署代理服务器(Nginx 配置见 6.1 节)
- 将代理服务器的固定 IP 添加到微信 IP 白名单
- 配置 Edge Function Secret
SUPERUN_WECHAT_API_PROXY_URL - 重新部署并验证连通性

