微信相关能力

This commit is contained in:
2026-01-30 17:25:30 +08:00
parent 4856a88d41
commit bf591095a2
43 changed files with 4297 additions and 391 deletions

View File

@@ -0,0 +1,564 @@
# 微信集成 API 文档
本文档详细说明微信 OAuth 登录和微信支付相关的 API 接口。
## 目录
- [认证说明](#认证说明)
- [错误码](#错误码)
- [API 接口](#api-接口)
- [1. 微信 OAuth 登录](#1-微信-oauth-登录)
- [2. 绑定微信账号](#2-绑定微信账号)
- [3. 微信 JSAPI 支付](#3-微信-jsapi-支付)
- [4. 微信 H5 支付](#4-微信-h5-支付)
- [5. 微信支付回调](#5-微信支付回调)
---
## 认证说明
### 公开接口
以下接口无需认证,可直接调用:
- `POST /api/c/v1/wechat/auth` - 微信 OAuth 登录
- `POST /api/callback/wechat-pay` - 微信支付回调
### 需要认证的接口
以下接口需要在请求头中携带 JWT Token
```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
- `POST /api/c/v1/bind-wechat` - 绑定微信账号(个人客户)
- `POST /api/h5/orders/:id/wechat-pay/jsapi` - 微信 JSAPI 支付H5认证
- `POST /api/h5/orders/:id/wechat-pay/h5` - 微信 H5 支付H5认证
---
## 错误码
微信集成相关的错误码:
| 错误码 | 说明 | HTTP 状态码 |
|--------|------|-------------|
| 1044 | 微信 OAuth 授权失败 | 400 |
| 1045 | 获取微信用户信息失败 | 400 |
| 1046 | 微信支付失败 | 400 |
| 1047 | 微信支付回调数据无效 | 400 |
| 1003 | 参数无效 | 400 |
| 1020 | 手机号已被使用 | 400 |
| 1021 | 个人客户不存在 | 404 |
| 1035 | 订单不存在 | 404 |
---
## API 接口
### 1. 微信 OAuth 登录
通过微信授权码登录或创建账号。如果用户首次登录,系统会自动创建账号。
**接口地址**
```
POST /api/c/v1/wechat/auth
```
**请求参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| code | string | ✅ | 微信授权码5分钟有效期一次性使用 |
**请求示例**
```json
{
"code": "071abc123456789def"
}
```
**响应参数**
| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码0表示成功 |
| msg | string | 响应消息 |
| data | object | 响应数据 |
| data.token | string | JWT Token用于后续请求认证 |
| data.customer_id | integer | 个人客户ID |
| data.phone | string | 手机号(未绑定时为空) |
| data.nickname | string | 昵称(微信昵称) |
| data.is_new_user | boolean | 是否新用户 |
| timestamp | string | 响应时间戳RFC3339格式 |
**响应示例**
```json
{
"code": 0,
"msg": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MTIzLCJleHAiOjE3MDY2OTI4MDB9.abc123def456",
"customer_id": 123,
"phone": "138****8888",
"nickname": "微信用户",
"is_new_user": false
},
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**错误响应**
```json
{
"code": 1044,
"msg": "微信 OAuth 授权失败",
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**业务逻辑**
1. 验证授权码是否有效
2. 调用微信API获取用户 OpenID 和 UnionID
3. 查找数据库是否存在该微信用户:
- **存在**:返回已有账号的 Token
- **不存在**:创建新账号,返回新账号的 Token
4. 新用户状态为"未绑定手机号",后续需要绑定手机号才能使用完整功能
**注意事项**
- 授权码code只能使用一次重复使用会失败
- 授权码有效期为5分钟
- Token 有效期为7天
- 新用户首次登录时 `phone` 字段为空,需要引导绑定手机号
---
### 2. 绑定微信账号
将当前登录的个人客户账号绑定到微信。
**接口地址**
```
POST /api/c/v1/bind-wechat
```
**认证方式**
需要携带 JWT Token个人客户
**请求参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| code | string | ✅ | 微信授权码 |
**请求示例**
```json
{
"code": "071abc123456789def"
}
```
**响应参数**
| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码0表示成功 |
| msg | string | 响应消息 |
| timestamp | string | 响应时间戳 |
**响应示例**
```json
{
"code": 0,
"msg": "绑定成功",
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**错误响应**
```json
{
"code": 1020,
"msg": "该微信号已被其他账号绑定",
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**业务逻辑**
1. 验证授权码是否有效
2. 获取微信 OpenID 和 UnionID
3. 检查该微信号是否已被其他账号绑定
4. 更新当前账号的微信绑定信息
**注意事项**
- 一个微信号只能绑定一个账号
- 绑定后无法解绑(需联系管理员)
- 绑定成功后,可以使用微信登录
---
### 3. 微信 JSAPI 支付
创建微信 JSAPI 支付订单(微信内网页支付)。
**接口地址**
```
POST /api/h5/orders/:id/wechat-pay/jsapi
```
**认证方式**
需要携带 H5 Token。
**路径参数**
| 参数 | 类型 | 说明 |
|------|------|------|
| id | integer | 订单ID |
**请求参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| open_id | string | ✅ | 用户的微信 OpenID在公众号内获取 |
**请求示例**
```json
{
"open_id": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M"
}
```
**响应参数**
| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码0表示成功 |
| msg | string | 响应消息 |
| data | object | 响应数据 |
| data.prepay_id | string | 预支付交易会话标识 |
| data.pay_config | object | 支付配置直接传给微信JSAPI |
| data.pay_config.appId | string | 公众号AppID |
| data.pay_config.timeStamp | string | 时间戳 |
| data.pay_config.nonceStr | string | 随机字符串 |
| data.pay_config.package | string | 订单详情扩展字符串 |
| data.pay_config.signType | string | 签名方式RSA |
| data.pay_config.paySign | string | 签名 |
| timestamp | string | 响应时间戳 |
**响应示例**
```json
{
"code": 0,
"msg": "支付订单创建成功",
"data": {
"prepay_id": "wx30123456789012345678901234567890",
"pay_config": {
"appId": "wxabcdef1234567890",
"timeStamp": "1706606400",
"nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
"package": "prepay_id=wx30123456789012345678901234567890",
"signType": "RSA",
"paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7JS..."
}
},
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**错误响应**
```json
{
"code": 1035,
"msg": "订单不存在",
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**业务逻辑**
1. 验证订单是否存在且状态为"待支付"
2. 验证订单归属(只能支付自己的订单)
3. 调用微信支付API创建预支付订单
4. 生成支付配置(包含签名)
5. 返回支付配置给前端
**前端调用示例**
```javascript
// 获取支付配置
const res = await fetch(`/api/h5/orders/${orderId}/wechat-pay/jsapi`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${h5Token}`
},
body: JSON.stringify({ open_id: openId })
});
const result = await res.json();
// 调用微信JSAPI支付
wx.chooseWXPay({
...result.data.pay_config,
success: function(res) {
console.log('支付成功', res);
},
fail: function(res) {
console.log('支付失败', res);
}
});
```
**注意事项**
- 只能在微信内网页中使用
- OpenID 需要通过公众号 OAuth 获取
- 支付有效期为2小时
- 订单只能支付一次
---
### 4. 微信 H5 支付
创建微信 H5 支付订单(微信外浏览器支付)。
**接口地址**
```
POST /api/h5/orders/:id/wechat-pay/h5
```
**认证方式**
需要携带 H5 Token。
**路径参数**
| 参数 | 类型 | 说明 |
|------|------|------|
| id | integer | 订单ID |
**请求参数**
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| scene_info | object | ❌ | 场景信息 |
| scene_info.payer_client_ip | string | ❌ | 用户客户端IP |
| scene_info.h5_type | string | ❌ | H5类型Wap/IOS/Android |
**请求示例**
```json
{
"scene_info": {
"payer_client_ip": "123.12.12.123",
"h5_type": "Wap"
}
}
```
**响应参数**
| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码0表示成功 |
| msg | string | 响应消息 |
| data | object | 响应数据 |
| data.h5_url | string | H5 支付跳转链接 |
| timestamp | string | 响应时间戳 |
**响应示例**
```json
{
"code": 0,
"msg": "H5 支付订单创建成功",
"data": {
"h5_url": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx30123456789012345678901234567890&package=3583359058"
},
"timestamp": "2025-01-30T12:00:00+08:00"
}
```
**前端调用示例**
```javascript
// 创建 H5 支付订单
const res = await fetch(`/api/h5/orders/${orderId}/wechat-pay/h5`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${h5Token}`
},
body: JSON.stringify({
scene_info: {
payer_client_ip: clientIp,
h5_type: 'Wap'
}
})
});
const result = await res.json();
// 跳转到微信 H5 支付页面
if (result.code === 0) {
const returnUrl = encodeURIComponent(`https://your-domain.com/orders/${orderId}`);
window.location.href = `${result.data.h5_url}&redirect_url=${returnUrl}`;
}
```
**注意事项**
- 适用于微信外浏览器
- 支付完成后会跳转到 `redirect_url`需URL编码
- 支付有效期为5分钟
- 需要在微信商户平台配置 H5 支付域名
---
### 5. 微信支付回调
接收微信支付的异步通知。
**接口地址**
```
POST /api/callback/wechat-pay
```
**认证方式**
无需认证(由微信签名验证)。
**请求说明**
该接口由微信支付系统调用,开发者无需主动调用。
**请求头**
| 参数 | 说明 |
|------|------|
| Wechatpay-Serial | 微信支付平台证书序列号 |
| Wechatpay-Signature | 微信签名 |
| Wechatpay-Timestamp | 微信时间戳 |
| Wechatpay-Nonce | 微信随机串 |
**请求体**
微信发送的加密数据JSON格式
**响应**
成功处理返回 HTTP 200
```json
{
"code": "SUCCESS",
"message": "成功"
}
```
失败返回 HTTP 500
```json
{
"code": "FAIL",
"message": "失败原因"
}
```
**处理流程**
1. 验证微信签名PowerWeChat 自动处理)
2. 解密通知数据
3. 提取支付结果(交易状态、金额、订单号等)
4. 更新订单状态为"已支付"
5. 触发异步任务:
- 分佣计算
- 套餐分配
- 钱包充值
6. 返回成功响应给微信
**幂等性保证**
系统会检查订单状态,避免重复处理:
- 如果订单已支付,直接返回成功
- 如果订单不存在,返回失败
- 使用数据库事务确保原子性
**重试机制**
微信会在以下情况重试:
- 商户系统未返回响应
- 返回 HTTP 状态码不是 200
- 返回结果为 FAIL
重试规则:
- 15秒后第1次重试
- 30秒后第2次重试
- 3分钟后第3次重试
- 最多重试3次
**注意事项**
- 接口必须在 **10秒内** 返回响应
- 必须返回正确的 JSON 格式
- 签名验证失败会记录日志但不影响服务
- 处理失败会自动重试,无需手动干预
---
## 测试建议
### 开发环境测试
1. **OAuth 登录测试**
- 使用微信测试号(公众号测试账号)
- 在本地配置内网穿透ngrok、frp等
- 测试授权流程和账号创建
2. **支付功能测试**
- 使用 0.01 元小额订单测试
- 验证支付流程和回调处理
- 测试完成后可通过退款功能退回
3. **回调测试**
- 使用微信支付沙箱环境(需申请)
- 或者使用 Postman 模拟回调请求
- 验证幂等性和重试机制
### 生产环境测试
1. 使用真实商户号和公众号
2. 配置正确的 HTTPS 域名
3. 小额订单测试(建议 0.01 元)
4. 监控日志确认回调正常
---
## 相关文档
- [使用指南](./使用指南.md) - 详细的配置和部署说明
- [环境变量配置](../environment-variables.md) - 所有环境变量说明
- [README](../../README.md) - 项目整体说明