- 准备工作
- 已认证的微信小程序
- 已开通微信支付商户号
- 小程序后台已关联商户号
- 配置支付回调域名
- 后端实现流程
a) 统一下单接口
@RestController
@RequestMapping("/api/pay")
public class WxPayController {
@Autowired
private WxPayService wxPayService;
@PostMapping("/create")
public Result createOrder(@RequestBody OrderDTO orderDTO) {
try {
// 1. 创建统一下单请求对象
WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
request.setBody(orderDTO.getBody());
request.setOutTradeNo(orderDTO.getOrderNo());
request.setTotalFee(orderDTO.getTotalFee());
request.setSpbillCreateIp(orderDTO.getClientIp());
request.setNotifyUrl("https://你的域名/api/pay/notify");
request.setTradeType("JSAPI");
request.setOpenid(orderDTO.getOpenid()); // 小程序的openid
// 2. 调用统一下单接口
WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
// 3. 生成支付参数
Map<String, String> payInfo = new HashMap<>();
payInfo.put("appId", wxPayService.getConfig().getAppId());
payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
payInfo.put("nonceStr", WxPayUtil.generateNonceStr());
payInfo.put("package", "prepay_id=" + result.getPrepayId());
payInfo.put("signType", "RSA");
payInfo.put("paySign", WxPayUtil.generateSignature(payInfo, wxPayService.getConfig().getPrivateKey()));
return Result.success(payInfo);
} catch (WxPayException e) {
return Result.error("创建支付订单失败");
}
}
}
b) 支付回调处理
@PostMapping("/notify")
public String payNotify(HttpServletRequest request, HttpServletResponse response) {
try {
// 1. 解析支付结果通知
WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(request.getInputStream());
// 2. 验证签名
if (notifyResult.getResultCode().equals("SUCCESS")) {
// 3. 处理业务逻辑
String orderNo = notifyResult.getOutTradeNo();
// 更新订单状态
orderService.updateOrderStatus(orderNo, OrderStatus.PAID);
// 4. 返回成功响应
return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";
}
} catch (WxPayException e) {
return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>";
}
}
- 小程序端实现
// pages/pay/pay.js
Page({
data: {
orderNo: '',
totalFee: 0
},
// 发起支付
handlePay() {
wx.request({
url: 'https://你的域名/api/pay/create',
method: 'POST',
data: {
orderNo: this.data.orderNo,
totalFee: this.data.totalFee,
body: '商品描述',
clientIp: '127.0.0.1' // 实际应该是用户真实IP
},
success: (res) => {
if (res.data.code === 0) {
const payParams = res.data.data;
// 调起支付
wx.requestPayment({
timeStamp: payParams.timeStamp,
nonceStr: payParams.nonceStr,
package: payParams.package,
signType: payParams.signType,
paySign: payParams.paySign,
success: (res) => {
// 支付成功
wx.showToast({
title: '支付成功',
icon: 'success'
});
// 跳转到订单详情页
wx.redirectTo({
url: '/pages/order/detail?orderNo=' + this.data.orderNo
});
},
fail: (err) => {
// 支付失败
wx.showToast({
title: '支付失败',
icon: 'none'
});
}
});
}
}
});
}
});
- 配置文件示例
wx:
pay:
appId: 小程序appId
mchId: 商户号
mchKey: 商户密钥
keyPath: 商户证书路径
notifyUrl: https://你的域名/api/pay/notify
- 关键注意事项
- 签名验证:必须验证签名,确保支付安全
- 金额单位:金额单位为分,例如:1元 = 100分
- openid获取:确保正确获取用户的openid
- 订单号唯一性:商户订单号必须唯一
- 超时处理:设置合理的支付超时时间
- 异常处理:做好各种异常情况的处理
- 并发处理:注意并发支付的情况
- 安全建议
- 使用HTTPS进行通信
- 对敏感信息进行加密
- 实现防重放攻击机制
- 做好日志记录
- 定期更新证书
-
测试流程
-
使用微信支付沙箱环境进行测试
-
测试支付成功场景
-
测试支付失败场景
-
测试取消支付场景
-
测试网络异常场景
-
测试并发支付场景
-
常见问题处理
- 签名错误:检查签名算法和密钥配置
- 支付超时:检查网络和超时设置
- 重复支付:做好订单状态管理
- 回调失败:检查回调地址配置和网络
-
开发建议
-
先使用沙箱环境开发
-
实现完整的日志记录
-
做好异常处理
-
实现订单状态管理
-
添加支付结果查询接口
-
实现订单退款功能
-
添加支付统计功能
-
代码优化建议
- 使用统一的异常处理
- 实现支付结果查询接口
- 添加支付超时处理
- 实现订单状态管理
- 添加支付日志记录
- 实现防重复支付机制
我来详细介绍如何配置微信支付回调域名的详细步骤:
- 登录微信支付商户平台
- 访问 pay.weixin.qq.com/
- 使用商户号登录
- 进入配置页面
- 点击左侧菜单 “产品中心”
- 选择 “开发配置”
- 找到 “支付回调配置” 部分
- 配置回调域名
-
点击 “添加” 按钮
-
填写你的服务器域名(不需要带协议头和路径)
- 例如:
api.yourdomain.com - 注意:不能填写 IP 地址
- 不能带
http://或https:// - 不能带端口号
- 不能带路径
- 例如:
- 域名要求
- 必须是已备案的域名
- 必须配置了 SSL 证书(必须使用 HTTPS)
- 域名必须可以正常访问
- 建议使用专门的支付回调域名
- 验证配置
-
配置完成后,系统会自动验证域名
-
验证内容包括:
- 域名是否可访问
- 是否支持 HTTPS
- 证书是否有效
- 注意事项
- 一个商户号最多可以配置 5 个回调域名
- 域名配置后需要等待审核(一般 1-2 个工作日)
- 建议使用专门的子域名用于支付回调
- 确保服务器防火墙允许微信服务器的访问
- 测试验证
- 配置完成后,可以使用微信支付提供的测试工具进行验证
- 在商户平台 -> 开发配置 -> 支付回调配置
- 点击 “测试” 按钮
- 系统会发送测试通知到你的服务器
- 常见问题处理
-
如果验证失败,检查:
- 域名是否正确
- SSL 证书是否有效
- 服务器是否可访问
- 防火墙是否允许访问
- 域名是否已备案
- 配置示例
正确配置:
api.yourdomain.com
错误配置:
http://api.yourdomain.com
https://api.yourdomain.com
api.yourdomain.com:8080
api.yourdomain.com/notify
- 安全建议
- 使用专门的子域名
- 配置 SSL 证书
- 设置访问白名单
- 做好日志记录
- 定期检查证书有效期
- 验证回调配置
@RestController
@RequestMapping("/api/pay")
public class WxPayController {
@PostMapping("/notify")
public String payNotify(HttpServletRequest request, HttpServletResponse response) {
try {
// 1. 获取通知数据
String xmlData = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
// 2. 记录日志
log.info("收到支付回调通知:{}", xmlData);
// 3. 解析通知数据
WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData);
// 4. 验证签名
if (notifyResult.getResultCode().equals("SUCCESS")) {
// 5. 处理业务逻辑
String orderNo = notifyResult.getOutTradeNo();
// 更新订单状态
orderService.updateOrderStatus(orderNo, OrderStatus.PAID);
// 6. 返回成功响应
return "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";
}
} catch (Exception e) {
log.error("处理支付回调异常", e);
return "<xml><return_code><![CDATA[FAIL]]></return_code></xml>";
}
}
}
- 配置检查清单
- 域名已备案
- 配置了 SSL 证书
- 域名可以正常访问
- 服务器防火墙配置正确
- 回调接口可以正常响应
- 日志记录完善
- 异常处理完善
- 签名验证正确
- 响应格式正确
- 测试验证通过
- 监控建议
- 监控回调接口的可用性
- 监控 SSL 证书有效期
- 监控服务器负载
- 监控异常情况
- 设置告警机制
- 维护建议
- 定期检查证书有效期
- 定期检查域名配置
- 定期检查服务器状态
- 定期检查日志记录
- 定期更新安全配置