推荐手动封装 wechatpy + 自建支付视图,因其控制力强、调试清晰,可避免 django-wechat-pay 因长期未维护导致的 django 4.x 兼容问题、硬编码 md5 签名、notify_url 路径错误及异步通知丢失等坑。

直接用 django-wechat-pay 有坑,推荐手动封装官方 wechatpy + 自建支付视图,控制力强、调试清晰、避免签名失效和异步通知丢失。
为什么别急着装 django-wechat-pay
这个包长期未维护,Django 4.x+ 下 get_absolute_url 调用失败、回调视图不兼容 class-based view、签名生成逻辑硬编码微信旧版 v2 签名规则(sign_type=MD5),而现网商户多数已强制切到 HMAC-SHA256。更麻烦的是它把 notify_url 写死成相对路径,导致微信服务器回调 404。
实操建议:
- 卸载
django-wechat-pay:pip uninstall django-wechat-pay - 改用
wechatpy(官方推荐 SDK,持续更新):pip install wechatpy - 确保你的 Django 项目已配置
ALLOWED_HOSTS包含微信回调域名(如pay.example.com),否则通知请求会被 Django 拒绝
如何生成统一下单参数并返回 JSAPI 支付所需 jsapi_parameters
微信 JSAPI 支付要求前端调用 WXJSSDK.chooseWXPay,其入参 jsapi_parameters 必须由后端签名生成,不能前端拼接。关键点是:时间戳必须是字符串格式的秒级时间戳(不是毫秒),nonce_str 必须每次请求唯一,package 字段值固定为 prepay_id=wx123...。
示例视图片段(需替换 APPID、MCH_ID、API_KEY):
from wechatpy.pay import WeChatPay
from wechatpy.pay.api import WeChatOrder
<p>def create_jsapi_order(request):
client = WeChatPay(
appid="wxd678efh567hg6787",
api_key="your_api_key_here", # 微信商户平台 API 密钥(32位)
mch_id="1230000109",
mch_cert="/path/to/apiclient_cert.pem",
mch_key="/path/to/apiclient_key.pem",
)
order = client.order.create(
trade_type="JSAPI",
body="会员续费",
out_trade_no="ORDER_20240520_001",
total_fee=100, # 单位:分
notify_url="<a href="https://www.php.cn/link/8359bc4376e89b729d92ddd9b8a53c46">https://www.php.cn/link/8359bc4376e89b729d92ddd9b8a53c46</a>",
user_id="oAbc1234567890xyz", # 用户 openid,从登录态获取
)
jsapi_params = client.jsapi.get_jsapi_params(
prepay_id=order["prepay_id"],
nonce_str=order["nonce_str"], # 必须复用下单时的 nonce_str
timestamp=str(int(time.time())), # 注意:字符串,秒级
)
return JsonResponse({"jsapi_parameters": jsapi_params})
</p>
如何安全处理微信支付异步通知(notify_url)
微信服务器会以 POST 方式向你配置的 notify_url 发送 XML 数据,且**不带任何 HTTP 头认证**,只靠签名验证。常见错误包括:用 request.body.decode() 直接解析却忽略 Content-Type: application/xml;或未原样返回 <xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml> 导致微信重试。
正确做法:
- 视图必须允许 POST,且禁用 CSRF(加
@csrf_exempt) - 用
wechatpy的parse_xml解析原始 body,不要走 Django 的request.POST - 调用
client.parse_payment_notify验证签名,失败则返回FAILXML - 业务逻辑(如更新订单状态)必须在验签通过后执行,且建议加数据库锁或幂等判断(
out_trade_no唯一索引)
调试时最常卡住的三个地方
微信支付本地调试几乎必踩:
-
Invalid signature:90% 是因为API_KEY填了商户平台「APIv3 密钥」(32位)而不是「API 密钥」(32位 MD5 key),二者位置不同,别混淆 - 回调收不到:检查 Nginx/Apache 是否转发了原始 XML body(禁用
proxy_buffering,加proxy_set_header Content-Type application/xml;) - 前端
chooseWXPay报错invalid signature:确认传入的jsapi_parameters中timestamp是字符串,且前后端系统时间差不超过 5 分钟(微信校验严格)
微信支付本身不难,难在签名链路长、环节多、错误反馈模糊。把签名生成、验签、回调响应三处逻辑拆开独立测试,比堆砌一个“全自动”包更可靠。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











