作为一名独立开发者,在这个年代一定要会各种三方支付的接入。这里以微信支付为例,本以为官方文档足够详细,结果在签名验证、证书配置、异步通知等环节踩了无数坑。本文将结合我的真实开发经历,分享如何用 Python 实现 《 微信扫码支付(Native 支付)》 的完整流程,包括商户号申请、API 调用、回调处理等核心环节,并附上避坑指南,适合想快速落地支付功能的开发者参考。
https://your-domain.com/pay/callback
)# 安装官方SDK(推荐)
pip install wechatpay-v3
# 或使用第三方封装库(适合快速开发)
pip install python-wechatpay-native
import wechatpay_v3
from wechatpay_v3 import WeChatPay, WeChatPayType
# 初始化客户端(需替换为自己的证书路径和密钥)
wechat_pay = WeChatPay(
mchid="你的商户号",
private_key_path="apiclient_key.pem", # 商户私钥文件
wechat_cert_path="wechatpay_cert.pem" # 微信支付平台证书
)
# 构建订单参数
order_params = {
"out_trade_no": "20231025001", # 商户订单号(需唯一)
"total": {
"amount": 1, # 订单金额(单位:分)
"currency": "CNY"
},
"description": "测试商品购买",
"notify_url": "https://your-domain.com/pay/notify" # 异步通知地址
}
# 调用Native支付接口
response = wechat_pay.native.create(order_params)
code_url = response["code_url"] # 支付二维码链接
# 生成二维码图片(需安装qrcode库)
import qrcode
qr = qrcode.QRCode(version=1, box_size=10)
qr.add_data(code_url)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
img.save("pay_qr.png")
# 查询订单状态
order = wechat_pay.native.query(out_trade_no="20231025001")
print(f"订单状态:{order['trade_state']}") # SUCCESS/FAIL/UNPAID等
# 申请退款(需确保订单已支付)
refund_params = {
"out_trade_no": "20231025001",
"out_refund_no": "20231025001_REFUND", # 商户退款单号
"reason": "用户取消订单",
"amount": {
"refund": 1, # 退款金额(分)
"total": 1,
"currency": "CNY"
}
}
refund_response = wechat_pay.refund.create(refund_params)
print(f"退款状态:{refund_response['status']}")
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/pay/notify', methods=['POST'])
def wechatpay_notify():
# 获取通知原始数据与签名
notify_data = request.data.decode('utf-8')
signature = request.headers.get('Wechatpay-Signature')
# 验证签名(需使用微信支付平台证书)
try:
wechat_pay.verify_signature(notify_data, signature)
except Exception as e:
return jsonify({"code": "FAIL", "message": "签名验证失败"}), 400
# 解析通知内容
notify_json = json.loads(notify_data)
if notify_json["event_type"] == "TRANSACTION.SUCCESS":
# 处理订单完成逻辑(如修改订单状态、发放权益等)
handle_paid_order(notify_json["resource"]["out_trade_no"])
return jsonify({"code": "SUCCESS"})
return jsonify({"code": "SUCCESS"})
Wechatpay-Timestamp
(防止重放攻击)和Wechatpay-Nonce
(随机数)现象:调用创建订单接口返回INVALID_SIGN
排查过程:
解决方案:
wechatpay_v3.certificates.query()
接口自动获取最新平台证书排查步骤:
ngrok http 5000
)# 订单表增加唯一索引(out_trade_no)
CREATE UNIQUE INDEX idx_out_trade_no ON orders(out_trade_no);
# 处理通知时先查询数据库,避免重复处理
def handle_paid_order(out_trade_no):
if db.query(Order).filter_by(out_trade_no=out_trade_no).first():
return # 已处理过,直接返回
# 执行订单完成逻辑
# 定义订单状态枚举
class OrderStatus(Enum):
UNPAID = "未支付"
PAID = "已支付"
REFUNDING = "退款中"
REFUNDED = "已退款"
CLOSED = "已关闭"
微信支付开发的核心难点在于安全机制和异步流程处理,但掌握套路后会发现其设计非常严谨。回顾整个开发过程,我最大的体会是:一定要严格按照官方文档调试,遇到问题先排查参数和签名,再考虑代码逻辑。目前我的支付系统已稳定运行 8 个月,处理超过 2 万笔交易,故障率低于 0.05%。