微信支付现在普及了!我用Python写个微信小程序支付功能!无敌

用户头像
北京/设计爱好者/4年前/64浏览
微信支付现在普及了!我用Python写个微信小程序支付功能!无敌
用户头像
dasein58

微信支付现在普及了!我用Python写个微信小程序支付功能!无敌

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

  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="api.weixin.qq/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="api.mch.weixin.qq/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密钥两个弄错了,当然如果不是还有可能是其他问题,解决方案链接 cnblogs/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)

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

  5.安全问题

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

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

  最后送给大家一段祝福

  # _oo8oo_

  # o8888888o

  # 88" . "88

  # (| -_- |)

  # 0\=/0

  # ___/'==='\___

  # .' \\| |# '.

  # / \\||| : |||# \

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

  # | | \\\ - #/ | |

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

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

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

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

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

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

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

  #

  #

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

  #

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

  啦啦啦


0
阅读原文
|
举报
|
收藏
分享
相关推荐
评论
用户头像
评论你的想法~
表情
喜欢TA的作品吗?喜欢就快来夸夸TA吧!
推荐素材
乐陶创意体验工坊标志设计
中国风书法汉字字体设计其他
卡通兔子插画
苏门答腊虎母子插画
浙江省区位分析图
香盒包装设计国风国潮通用香礼盒
人物运动系列插画
小青龙IP吉祥物系列插画设计
红黑色简约现代风格|个人作品集排版简历模板
新能源腊八节海报
国画水墨江南山水画装饰画电视背景墙装饰画
黑白荧光色实验性风格|个人作品集排版简历模板
彩灯_花灯_春节彩灯_春节花灯_马年彩灯_马年花灯
人物网球运动、棒球运动动态插画
头发1
我要奋斗
汉堡插画
二十四节气图片之霜降
love玫瑰花
 ps常用偷懒笔刷
木纹贴图设计师常用
玫瑰
中秋佳节花好月圆
宠物纪念相册H5模板系列 · 温馨治愈系 · 三款主题
炫光
你可能喜欢
相关收藏夹
大家都在看
登录注册