美文网首页python热爱者Python新世界
微信二次开发案例,python制作微信支付小程序!

微信二次开发案例,python制作微信支付小程序!

作者: 48e0a32026ae | 来源:发表于2018-11-15 15:10 被阅读2次

    由于最近自己在做小程序的支付,就在这里简单介绍一下讲一下用python做小程序支付这个流程。当然在进行开发之前还是建议读一下具体的流程,清楚支付的过程。


    1.支付交互流程

    当然具体的参数配置可以参考官方文档

    https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1

    2.获取openid(微信用户标识)

    1 import requests

    2

    3 from config import APPID, SECRET

    4

    5

    6 class OpenidUtils(object):

    7

    8 def __init__(self, jscode):

    9 self.url = "https://api.weixin.qq.com/sns/jscode2session"

    10 self.appid = APPID # 小程序id

    11 self.secret = SECRET # 不要跟后面支付的key搞混

    12 self.jscode = jscode # 前端传回的动态jscode

    13

    14 def get_openid(self):

    15 # url一定要拼接,不可用传参方式

    16 url = self.url + "?appid=" + self.appid + "&secret=" + self.secret + "&js_code=" + self.jscode + "&grant_type=authorization_code"

    17 r = requests.get(url)

    18 print(r.json())

    19 openid = r.json()['openid']

    20

    21 return openid

    3.支付请求

    1 # -*- coding:utf-8 -*-

    2 import requests

    3 import hashlib

    4 import xmltodict

    5 import time

    6 import random

    7 import string

    8 import urllib2

    9 import sys

    10

    11

    12 class WX_PayToolUtil():

    13 """ 微信支付工具 """

    14

    15 def __init__(self, APP_ID, MCH_ID, API_KEY, NOTIFY_URL):

    16 self._APP_ID = APP_ID # 小程序ID

    17 self._MCH_ID = MCH_ID # # 商户号

    18 self._API_KEY = API_KEY

    19 self._UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 接口链接

    20 self._NOTIFY_URL = NOTIFY_URL # 异步通知

    21

    22 def generate_sign(self, param):

    23 '''生成签名'''

    24 stringA = ''

    25 ks = sorted(param.keys())

    26 # 参数排序

    27 for k in ks:

    28 stringA += (k + '=' + param[k] + '&')

    29 # 拼接商户KEY

    30 stringSignTemp = stringA + "key=" + self._API_KEY

    31 # md5加密,也可以用其他方式

    32 hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))

    33 sign = hash_md5.hexdigest().upper()

    34 return sign

    35

    36 '''

    37 # python2另外一种实现方法

    38 def generate_sign(self, params):

    39 ret = []

    40 for k in sorted(params.keys()):

    41 if (k != 'sign') and (k != '') and (params[k] is not None):

    42 ret.append('%s=%s' % (k, params[k]))

    43 params_str = '&'.join(ret)

    44 params_str = '%(params_str)s&key=%(partner_key)s' % {'params_str': params_str, 'partner_key': key}

    45

    46 reload(sys)

    47 sys.setdefaultencoding('utf8')

    48

    49 params_str = hashlib.md5(params_str.encode('utf-8')).hexdigest()

    50 sign = params_str.upper()

    51 return sign

    52 '''

    53

    54 def getPayUrl(self, orderid, openid, goodsPrice, **kwargs):

    55 """向微信支付端发出请求,获取url"""

    56 key = self._API_KEY

    57 nonce_str = ''.join(random.sample(string.letters + string.digits, 30)) # 生成随机字符串,小于32位

    58 params = {

    59 'appid': self._APP_ID, # 小程序ID

    60 'mch_id': self._MCH_ID, # 商户号

    61 'nonce_str': nonce_str, # 随机字符串

    62 "body": '测试订单', # 支付说明

    63 'out_trade_no': orderid, # 生成的订单号

    64 'total_fee': str(goodsPrice), # 标价金额

    65 'spbill_create_ip': "127.0.0.1", # 小程序不能获取客户ip,web用socekt实现

    66 'notify_url': self._NOTIFY_URL,

    67 'trade_type': "JSAPI", # 支付类型

    68 "openid": openid, # 用户id

    69 }

    70 # 生成签名

    71 params['sign'] = self.generate_sign(params)

    72

    73 # python3一种写法

    74 param = {'root': params}

    75 xml = xmltodict.unparse(param)

    76 response = requests.post(self._UFDODER_URL, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})

    77 # xml 2 dict

    78 msg = response.text

    79 xmlmsg = xmltodict.parse(msg)

    80 # 4. 获取prepay_id

    81 if xmlmsg['xml']['return_code'] == 'SUCCESS':

    82 if xmlmsg['xml']['result_code'] == 'SUCCESS':

    83 prepay_id = xmlmsg['xml']['prepay_id']

    84 # 时间戳

    85 timeStamp = str(int(time.time()))

    86 # 5. 五个参数

    87 data = {

    88 "appId": self._APP_ID,

    89 "nonceStr": nonce_str,

    90 "package": "prepay_id=" + prepay_id,

    91 "signType": 'MD5',

    92 "timeStamp": timeStamp,

    93 }

    94 # 6. paySign签名

    95 paySign = self.generate_sign(data)

    96 data["paySign"] = paySign # 加入签名

    97 # 7. 传给前端的签名后的参数

    98 return data

    99

    100 # python2一种写法

    101 '''

    102 request_xml_str = ''

    103 for key, value in params.items():

    104 if isinstance(value, str):

    105 request_xml_str = '%s<%s>' % (request_xml_str, key, value, key,)

    106 else:

    107 request_xml_str = '%s<%s>%s' % (request_xml_str, key, value, key,)

    108 request_xml_str = '%s' % request_xml_str

    109

    110 # 向微信支付发出请求,并提取回传数据

    111 res = urllib2.Request(self._UFDODER_URL, data=request_xml_str.encode("utf-8"))

    112 res_data = urllib2.urlopen(res)

    113 res_read = res_data.read()

    114 doc = xmltodict.parse(res_read)

    115 return_code = doc['xml']['return_code']

    116 if return_code == "SUCCESS":

    117 result_code = doc['xml']['result_code']

    118 if result_code == "SUCCESS":

    119 doc = doc['xml']

    120 data = {

    121 "appId": self._APP_ID,

    122 "nonceStr": nonce_str,

    123 "package": "prepay_id=" + doc["prepay_id"],

    124 "signType": 'MD5',

    125 "timeStamp": str(int(time.time())),

    126 }

    127 # paySign签名

    128 paySign = self.generate_sign(data)

    129 data["paySign"] = paySign # 加入签名

    130 return data

    131 else:

    132 err_des = doc['xml']['err_code_des']

    133 return err_des

    134 else:

    135 fail_des = doc['xml']['return_msg']

    136 return fail_des

    137 '''

    当然你可能会遇到的错误有签名错误,一般的情况是你的appSecret和商户号的API密钥两个弄错了,当然如果不是还有可能是其他问题,解决方案链接 https://www.cnblogs.com/wanghuijie/p/wxpay_sign_error.html 。

    其他的支付方式获取用户的ip地址可以通过 socket.gethostbyname(socket.gethostname()) 方法来获取。

    4.支付回调

    1 # 统一下单回调处理

    2

    3 import xmltodict

    4

    5 from django.http import HttpResponse

    6

    7 def payback(request):

    8 msg = request.body.decode('utf-8')

    9 xmlmsg = xmltodict.parse(msg)

    10

    11 return_code = xmlmsg['xml']['return_code']

    12

    13 if return_code == 'FAIL':

    14 # 官方发出错误

    15 return HttpResponse("""

    16 """,

    17 content_type='text/xml', status=200)

    18 elif return_code == 'SUCCESS':

    19 # 拿到这次支付的订单号

    20 out_trade_no = xmlmsg['xml']['out_trade_no']

    21

    22 # 根据需要处理业务逻辑

    23

    24 return HttpResponse("""

    25 """,

    26 content_type='text/xml', status=200)

    当然微信回调的参数有很多详细可以参考 、https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8

    5.安全问题

    在使用的过程中 商户系统对于支付结果通知的内容一定要做 签名验证,并校验返回的订单金额是否与商户侧的订单金额一致 ,防止数据泄漏导致出现“假通知”,造成资金损失。

    我在开发过程中的解决方式是在向微信支付端发起请求的时候, 把订单号,金额,签名等存入数据库,然后在回调函数那里进行校验判断 。在确认跟前面订单情况一样的情况下,才进行后续一系列的操作。

    最后送给大家一段祝福

    # _oo8oo_

    # o8888888o

    # 88" . "88

    # (| -_- |)

    # 0 = /0

    # ___/'==='___

    # .' \| |# '.

    # / \||| : |||#

    # / _||||| -:- |||||_

    # | | \ - #/ | |

    # | _| ''---/'' |_/ |

    #  .-__ '-' __/-. /

    # ___'. .' /--.-- '. .'___

    # ."" '< '.____<|>_/___.' >' "".

    # | | : `- `.:` _ /`:.`/ -` : | |

    #  `-. _ __ /__ _/ .-` / /

    # =====`-.____`.___ _____/ ___.`____.-`=====

    # `=---=`

    #

    #

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    #

    # 强大爷保佑 永不宕机/永无bug

    啦啦啦

    相关文章

      网友评论

        本文标题:微信二次开发案例,python制作微信支付小程序!

        本文链接:https://www.haomeiwen.com/subject/eyyyfqtx.html