Django 接入微信支付 详细说明

发布时间:2020-09-08 浏览量: 868 文章分类: python

先吐槽一下微信支付,竟然现在还用的是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_strsign 我们提交的字符串签名  # 需要和我们的对比一下,看看是否有出入
code_url = 这个是微信返回给我们的支付二维码url前端js调用第三方库 直接生成一个二维码就可以支付了

至此,微信接入完毕。然后封装一下代码,就可以开心跑起来了。