Django 接入微信支付 详细说明
先吐槽一下微信支付,竟然现在还用的是xml
的方式,确认让我研究了很久。
我的py环境python=3.6
,理论来说都支持,需要装一个额外的第三方库pip install xmltodict
用来处理xml
的相关数据格式。
关于接入支付的,可以点击这里查看
提前准备
- 微信支付需要注册
商户平台
https://pay.weixin.qq.com/ ,然后在产品中心
签约支付产品
开通JSAPI支付
、Native支付
即可。 - 在
账户中心
->API安全
->设置API秘钥
,可以设置一个随机字符串,然后记牢。 做好上面2步就可以开始接入了。
接入说明
官网这块的文档并没有说明python
相关的接入方法,官网接入文档 可以点击查看一下。我们这里主要用的是 API列表
->统一下单
来生成支付二维码。
首先需要先了解一下 下面这些字段,我只写必须要填写的,具体完整的可以查看官网文档
字段名 | 变量名 | 说明 |
---|---|---|
公众账号ID | appid | 在产品中心->Appid账号管理查看绑定 |
商户号 | mch_id | 在账户中心->商户信息->微信支付商户号 |
随机字符串 | nonce_str | python实现比较简单,直接str(uuid.uuid4()).replace("-","") |
签名 | sign | 这里是个坑,下面我会单独说 |
商品描述 | body | 付款的时候展示的标题 |
商户订单号 | out_trade_no | 根据自己的订单id,直接丢这里即可 |
标价金额 | total_fee | 这里也要额外注意,单位是分,所以不支持小数点 |
终端IP | spbill_create_ip | 直接把请求的IP传给他就好了 |
通知地址 | notify_url | 和支付宝接入的一样,通知我们付款结果的 |
交易类型 | trade_type | 我这里写的是NATIVE 根据自己的需要写即可 |
这里额外说一下官网提供了一个签名效验的的工具,点击这里
效验的时候,建议签名类型选择MD5
、效验方式选择自定义参数
,然后先跑通,在逐步完善。可以有效减少我们的接入时间。
签名这里,微信支付采用的MD5加密即可。因此直接使用python自带的hashlib
库。
import uuid,hashlib,time,xmltodict
#先定义好一些通用字段
mah_key = '你的API秘钥'
appid = '你的appid'
body = '支付商品名称'
mchid = '商户id'
nonce_str = str(uuid.uuid4()).replace("-","")
notify_url = '接收付款通知的URL'
out_trade_no = '你的订单ID'
total_fee = 1 # 价格
先定义好上面这些参数你的实现。
实现签名
需要先构建一个参数字典
params = {
'appid':appid, #公众账号ID
'mch_id':mchid, # 商户号
'body':body, #商品描述
'nonce_str':nonce_str, # 随机字符串
'total_fee':total_fee, # 标价金额
'spbill_create_ip':client_ip, #终端IP
'sign_type':'MD5',
'out_trade_no':out_trade_no, # 商户订单号
'notify_url':notify_url, # 通知地址
'trade_type':'NATIVE',
}
Mch_key = '' #API秘钥
stringA = '&'.join(["{0}={1}".format(k, params.get(k)) for k in sorted(params)])
stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key)
sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()
sign = sign.upper()
上面的sign
输入就是一个md5的加密串了,这里已经实现了
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段
◆ 在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。
接下来就是拼接需要给微信的xml
数据,因为我也没有很好的办法,就手动拼接了。大家如果有好的方法也可以告诉我
bodyData = '<xml>'
bodyData += '<appid><![CDATA[' + appid + ']]></appid>' # 小程序ID
bodyData += '<body><![CDATA[' + body + ']]></body>' # 商品描述
bodyData += '<detail><![CDATA[' + detail + ']]></detail>' # 商品描述
bodyData += '<mch_id><![CDATA[' + mchid +']]></mch_id>'
bodyData += '<nonce_str><![CDATA[' + nonce_str + ']]></nonce_str>'
bodyData += '<notify_url><![CDATA[' + notify_url + ']]></notify_url>'
bodyData += '<out_trade_no><![CDATA[' + out_trade_no + ']]></out_trade_no>'
bodyData += '<sign_type><![CDATA[' + 'MD5' + ']]></sign_type>'
bodyData += '<spbill_create_ip><![CDATA[' + client_ip + ']]></spbill_create_ip>'
bodyData += '<total_fee><![CDATA[' + str(total_fee) + ']]></total_fee>'
bodyData += '<trade_type><![CDATA[' + 'NATIVE' + ']]></trade_type>'
bodyData += '<sign>' + sign + '</sign>'
bodyData += '</xml>'
这个时间建议先不要着急,将这个xml
串打印出来,然后在前面提到的签名验证平台上先手动验证,看看到底是哪里出问题了。
按照上面的步骤验证,如果都是正确的,那就没有问题了。
发送给微信服务器
这里我用了requests
模块直接简单实现
respone = requests.post(url, bodyData.encode("utf-8"), headers={'Content-Type': 'application/xml'})
print(respone.content)
content = xmltodict.parse(respone.content)
print(content)
在成功调用后,微信官方会返回给我们下面一个这样的xml
串,告知我们结果
OrderedDict([('xml', OrderedDict([('return_code', 'SUCCESS'), ('return_msg', 'OK'), ('appid', ''), ('mch_id', ''), ('nonce_str', ''), ('sign', ''), ('result_code', 'SUCCESS'), ('prepay_id', ''), ('trade_type', 'NATIVE'), ('code_url', '')]))])
实际里面是有参数的,我删掉了一些关键参数,我们主要关注下面几个即可
result_code = SUCCESS/FAIL #正常情况应该都是 SUCCESS
nonce_str、sign 我们提交的字符串、签名 # 需要和我们的对比一下,看看是否有出入
code_url = 这个是微信返回给我们的支付二维码url,前端js调用第三方库 直接生成一个二维码就可以支付了。
至此,微信接入完毕。然后封装一下代码,就可以开心跑起来了。