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