565 lines
12 KiB
Markdown
565 lines
12 KiB
Markdown
# 微信集成 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) - 项目整体说明
|