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中常见的异常总结
Feb 20 Python
Python各类图像库的图片读写方式总结(推荐)
Feb 23 Python
用tensorflow构建线性回归模型的示例代码
Mar 05 Python
Python3.5局部变量与全局变量作用域实例分析
Apr 30 Python
简单了解python中的f.b.u.r函数
Nov 02 Python
python 项目目录结构设置
Feb 14 Python
python实现简单颜色识别程序
Feb 19 Python
python 实现在shell窗口中编写print不向屏幕输出
Feb 19 Python
如何基于windows实现python定时爬虫
May 01 Python
Python调用OpenCV实现图像平滑代码实例
Jun 19 Python
Prometheus开发中间件Exporter过程详解
Nov 30 Python
python利用while求100内的整数和方式
Nov 07 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
php数组函数序列之array_unique() - 去除数组中重复的元素值
2011/10/29 PHP
php实现图形显示Ip地址的代码及注释
2014/01/20 PHP
JavaScript实现删除电脑的关机键
2016/07/26 PHP
PHP中检索字符串的方法分析【strstr与substr_count方法】
2017/02/17 PHP
js给onclick事件赋值,动态传参数实例解说
2013/03/28 Javascript
javascript中对Attr(dom中属性)的操作示例讲解
2013/12/02 Javascript
fmt:formatDate的输出格式详解
2014/01/09 Javascript
推荐一款jQuery插件模板
2015/01/09 Javascript
一个超简单的jQuery回调函数例子(分享)
2016/08/08 Javascript
jQuery实现可拖拽的许愿墙效果【附demo源码下载】
2016/09/14 Javascript
JS制作类似选项卡切换的年历
2016/12/03 Javascript
详解数组Array.sort()排序的方法
2020/05/09 Javascript
JS解决移动web开发手机输入框弹出的问题
2017/03/31 Javascript
jacascript DOM节点——元素节点、属性节点、文本节点
2017/04/18 Javascript
react redux入门示例
2018/04/19 Javascript
vue项目打包之开发环境和部署环境的实现
2020/04/23 Javascript
[46:23]完美世界DOTA2联赛PWL S2 FTD vs Magma 第一场 11.20
2020/11/23 DOTA
在Python3中使用asyncio库进行快速数据抓取的教程
2015/04/02 Python
python实现发送邮件及附件功能
2021/03/02 Python
Django权限机制实现代码详解
2018/02/05 Python
python3.5基于TCP实现文件传输
2020/03/20 Python
python Pexpect 实现输密码 scp 拷贝的方法
2019/01/03 Python
python读写Excel表格的实例代码(简单实用)
2019/12/19 Python
Python基于Socket实现简单聊天室
2020/02/17 Python
在matplotlib中改变figure的布局和大小实例
2020/04/23 Python
numpy矩阵数值太多不能全部显示的解决
2020/05/14 Python
Backcountry旗下的户外商品闪购网站:steep&cheap
2016/09/22 全球购物
Happy Socks英国官网:购买五颜六色的袜子
2020/11/03 全球购物
人力资源行政经理自我评价
2013/10/23 职场文书
单位实习工作证明怎么写
2014/11/02 职场文书
作弊检讨书范文
2015/05/06 职场文书
党支部鉴定意见
2015/06/02 职场文书
钱学森电影观后感
2015/06/04 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
2019年个人工作总结范文(3篇)
2019/08/27 职场文书
Mysql案例刨析事务隔离级别
2021/09/25 MySQL