Python实现微信小程序支付功能


Posted in Python onJuly 25, 2019

正文

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

1.支付交互流程

当然具体的参数配置可以参考官方文档https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1

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

import requests
 from config import APPID, SECRET
 class OpenidUtils(object):
  def __init__(self, jscode):
   self.url = "https://api.weixin.qq.com/sns/jscode2session"
   self.appid = APPID # 小程序id
   self.secret = SECRET # 不要跟后面支付的key搞混
   self.jscode = jscode # 前端传回的动态jscode
  def get_openid(self):
   # url一定要拼接,不可用传参方式
   url = self.url + "?appid=" + self.appid + "&secret=" + self.secret + "&js_code=" + self.jscode + "&grant_type=authorization_code"
   r = requests.get(url)
   print(r.json())
   openid = r.json()['openid']
   return openid

3.支付请求

# -*- coding:utf-8 -*-
import requests
import hashlib
import xmltodict
import time
import random
import string
import urllib2
import sys
class WX_PayToolUtil():
 """ 微信支付工具 """
 def __init__(self, APP_ID, MCH_ID, API_KEY, NOTIFY_URL):
  self._APP_ID = APP_ID # 小程序ID
  self._MCH_ID = MCH_ID # # 商户号
  self._API_KEY = API_KEY
  self._UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 接口链接
  self._NOTIFY_URL = NOTIFY_URL # 异步通知
 def generate_sign(self, param):
   '''生成签名'''
   stringA = ''
   ks = sorted(param.keys())
   # 参数排序
   for k in ks:
    stringA += (k + '=' + param[k] + '&')
   # 拼接商户KEY
   stringSignTemp = stringA + "key=" + self._API_KEY
   # md5加密,也可以用其他方式
   hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))
   sign = hash_md5.hexdigest().upper()
   return sign
 '''
 # python2另外一种实现方法
 def generate_sign(self, params):
  ret = []
  for k in sorted(params.keys()):
   if (k != 'sign') and (k != '') and (params[k] is not None):
    ret.append('%s=%s' % (k, params[k]))
  params_str = '&'.join(ret)
  params_str = '%(params_str)s&key=%(partner_key)s' % {'params_str': params_str, 'partner_key': key}
  reload(sys)
  sys.setdefaultencoding('utf8')
  params_str = hashlib.md5(params_str.encode('utf-8')).hexdigest()
  sign = params_str.upper()
  return sign
 '''
 def getPayUrl(self, orderid, openid, goodsPrice, **kwargs):
  """向微信支付端发出请求,获取url"""
  key = self._API_KEY
  nonce_str = ''.join(random.sample(string.letters + string.digits, 30)) # 生成随机字符串,小于32位
  params = {
   'appid': self._APP_ID, # 小程序ID
   'mch_id': self._MCH_ID, # 商户号
   'nonce_str': nonce_str, # 随机字符串
   "body": '测试订单', # 支付说明
   'out_trade_no': orderid, # 生成的订单号
   'total_fee': str(goodsPrice), # 标价金额
   'spbill_create_ip': "127.0.0.1", # 小程序不能获取客户ip,web用socekt实现
   'notify_url': self._NOTIFY_URL,
   'trade_type': "JSAPI", # 支付类型
   "openid": openid, # 用户id
   }
  # 生成签名
  params['sign'] = self.generate_sign(params)
  # python3一种写法
  param = {'root': params}
  xml = xmltodict.unparse(param)
  response = requests.post(self._UFDODER_URL, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
  # xml 2 dict
  msg = response.text
  xmlmsg = xmltodict.parse(msg)
  # 4. 获取prepay_id
  if xmlmsg['xml']['return_code'] == 'SUCCESS':
   if xmlmsg['xml']['result_code'] == 'SUCCESS':
    prepay_id = xmlmsg['xml']['prepay_id']
    # 时间戳
    timeStamp = str(int(time.time()))
    # 5. 五个参数
    data = {
     "appId": self._APP_ID,
     "nonceStr": nonce_str,
     "package": "prepay_id=" + prepay_id,
     "signType": 'MD5',
     "timeStamp": timeStamp,
    }
    # 6. paySign签名
    paySign = self.generate_sign(data)
    data["paySign"] = paySign # 加入签名
    # 7. 传给前端的签名后的参数
    return data
  # python2一种写法
  '''
  request_xml_str = '<xml>'
  for key, value in params.items():
   if isinstance(value, str):
    request_xml_str = '%s<%s><![CDATA[%s]]></%s>' % (request_xml_str, key, value, key,)
   else:
    request_xml_str = '%s<%s>%s</%s>' % (request_xml_str, key, value, key,)
  request_xml_str = '%s</xml>' % request_xml_str
  # 向微信支付发出请求,并提取回传数据
  res = urllib2.Request(self._UFDODER_URL, data=request_xml_str.encode("utf-8"))
  res_data = urllib2.urlopen(res)
  res_read = res_data.read()
  doc = xmltodict.parse(res_read)
  return_code = doc['xml']['return_code']
  if return_code == "SUCCESS":
   result_code = doc['xml']['result_code']
   if result_code == "SUCCESS":
    doc = doc['xml']
    data = {
     "appId": self._APP_ID,
     "nonceStr": nonce_str,
     "package": "prepay_id=" + doc["prepay_id"],
     "signType": 'MD5',
     "timeStamp": str(int(time.time())),
    }
    # paySign签名
    paySign = self.generate_sign(data)
    data["paySign"] = paySign # 加入签名
    return data
   else:
    err_des = doc['xml']['err_code_des']
    return err_des 
  else:
   fail_des = doc['xml']['return_msg']
   return fail_des
  '''

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

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

4.支付回调

# 统一下单回调处理
import xmltodict
from django.http import HttpResponse
def payback(request):
 msg = request.body.decode('utf-8')
 xmlmsg = xmltodict.parse(msg)
 return_code = xmlmsg['xml']['return_code']
 if return_code == 'FAIL':
  # 官方发出错误
  return HttpResponse("""<xml><return_code><![CDATA[FAIL]]></return_code>
       <return_msg><![CDATA[Signature_Error]]></return_msg></xml>""",
       content_type='text/xml', status=200)
 elif return_code == 'SUCCESS':
  # 拿到这次支付的订单号
  out_trade_no = xmlmsg['xml']['out_trade_no']
  # 根据需要处理业务逻辑
  return HttpResponse("""<xml><return_code><![CDATA[SUCCESS]]></return_code>
       <return_msg><![CDATA[OK]]></return_msg></xml>""",
       content_type='text/xml', status=200)

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

在回调的时候可能遇到这样一个问题,支付成功以后没有调回调函数,有可能是回调地址是https然后改为http就行,遇到过这个坑,具体原因也不知道。服务器没有屏蔽https访问,https证书也没有问题,把https改为http最后就可以了。

5.安全问题

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

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

最后送给大家一段祝福

#         _oo8oo_
#         o8888888o
#         88" . "88
#         (| -_- |)
#         0\ = /0
#        ___/'==='\___
#        .' \\|  |# '.
#       / \\||| : |||# \
#       / _||||| -:- |||||_ \
#       | | \\\ - #/ | |
#       | \_| ''\---/'' |_/ |
#       \ .-\__ '-' __/-. /
#      ___'. .' /--.--\ '. .'___
#      ."" '< '.___\_<|>_/___.' >' "".
#     | | : `- \`.:`\ _ /`:.`/ -` : | |
#     \ \ `-. \_ __\ /__ _/ .-` / /
#    =====`-.____`.___ \_____/ ___.`____.-`=====
#         `=---=`
#
#
#    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#

总结

以上所述是小编给大家介绍的Python实现微信小程序支付功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
python高并发异步服务器核心库forkcore使用方法
Nov 26 Python
详解设计模式中的工厂方法模式在Python程序中的运用
Mar 02 Python
详解Python的Flask框架中生成SECRET_KEY密钥的方法
Jun 07 Python
python机器学习理论与实战(二)决策树
Jan 19 Python
python检索特定内容的文本文件实例
Jun 05 Python
django框架实现一次性上传多个文件功能示例【批量上传】
Jun 19 Python
Python3的socket使用方法详解
Feb 18 Python
浅谈Python 参数与变量
Jun 20 Python
python字典的值可以修改吗
Jun 29 Python
python中二分查找法的实现方法
Dec 06 Python
python画图时设置分辨率和画布大小的实现(plt.figure())
Jan 08 Python
基于Python实现将列表数据生成折线图
Mar 23 Python
Form表单及django的form表单的补充
Jul 25 #Python
python实现切割url得到域名、协议、主机名等各个字段的例子
Jul 25 #Python
python按修改时间顺序排列文件的实例代码
Jul 25 #Python
在python中用url_for构造URL的方法
Jul 25 #Python
对python中url参数编码与解码的实例详解
Jul 25 #Python
使用WingPro 7 设置Python路径的方法
Jul 24 #Python
python selenium 查找隐藏元素 自动播放视频功能
Jul 24 #Python
You might like
使用MaxMind 根据IP地址对访问者定位
2006/10/09 PHP
一个简单计数器的源代码
2006/10/09 PHP
php查询ip所在地的方法
2014/12/05 PHP
PHP实现一维数组转二维数组的方法
2015/02/25 PHP
PHP中TP5 上传文件的实例详解
2017/07/31 PHP
基于laravel缓冲cache的用法详解
2019/10/23 PHP
php判断数组是否为空的实例方法
2020/05/10 PHP
实现连缀调用的map方法(prototype)
2009/08/05 Javascript
JavaScript 三种创建对象的方法
2009/10/16 Javascript
js利用事件的阻止冒泡实现点击空白模态框的隐藏
2014/01/24 Javascript
js控制当再次点击按钮时的间隔时间
2014/06/03 Javascript
js实现简单锁屏功能实例
2015/05/27 Javascript
Bootstrap Table使用方法详解
2016/08/01 Javascript
js智能获取浏览器版本UA信息的方法
2016/08/08 Javascript
微信小程序 Windows2008 R2服务器配置TLS1.2方法
2016/12/05 Javascript
详解VUE-地区选择器(V-Distpicker)组件使用心得
2018/05/07 Javascript
Vue组件Draggable实现拖拽功能
2018/12/01 Javascript
node 解析图片二维码的内容代码实例
2019/09/11 Javascript
js找出5个数中最大的一个数和倒数第二大的数实现方法示例小结
2020/03/04 Javascript
Node在Controller层进行数据校验的过程详解
2020/08/28 Javascript
[52:36]VGJ.S vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python数组过滤实现方法
2015/07/27 Python
python脚本实现xls(xlsx)转成csv
2016/04/10 Python
python3.4用循环往mysql5.7中写数据并输出的实现方法
2017/06/20 Python
Python3中详解fabfile的编写
2018/06/24 Python
Python匿名函数/排序函数/过滤函数/映射函数/递归/二分法
2019/06/05 Python
python隐藏终端执行cmd命令的方法
2019/06/24 Python
Python元组 tuple的概念与基本操作详解【定义、创建、访问、计数、推导式等】
2019/10/30 Python
PyTorch中topk函数的用法详解
2020/01/02 Python
库房主管岗位职责
2013/12/31 职场文书
退休感言
2014/01/28 职场文书
外贸采购员岗位职责
2014/03/08 职场文书
股东协议书范本
2014/04/14 职场文书
群众路线教育实践活动自我剖析思想汇报
2014/10/04 职场文书
k8s部署redis cluster集群的实现
2021/06/24 Redis
Python实现将多张图片合成MP4视频并加入背景音乐
2022/04/28 Python