服务粉丝

我们一直在努力
当前位置:首页 > 科技 >

Win10基于Vue.js+Django+Python3微信扫码支付流程

日期: 来源:刘悦技术分享收集编辑:刘悦技术分享

之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内部支付的流程,然而实际上微信小程序有一定的局限性,也就是用户范围仅限于小程序内部生态圈,在生活中真正具有广泛性、高效性、使用方便性的支付方式还得是扫码支付,扫码的优点在于推广成本低,上至钓鱼台国宾馆,下至发廊地摊都能用,打印出来就完事了,而相比其他支付方式,现金的找零及假钞问题,信用卡的办理门槛、pos机的沉没成本,就算微信可集成的h5支付和小程序支付,奈何很多老年人根本不会用小程序和手机浏览器,更别说再进行支付操作了,所以基于二维码的扫码支付的确是非常符合国情的。

本次我们使用前后端分离项目Vue.js+Django来集成微信的扫码支付功能,体验一下21世纪泛用性最高的支付方式,首先注册微信公众平台:https://mp.weixin.qq.com

获得开发者id和秘钥(appid & appsecret)

同时确保获取微信支付接口的权限:

随后注册微信支付商户平台:https://pay.weixin.qq.com/

获取微信支付的商户号(在账户信息页面):

获取微信支付接口的秘钥(账户中心->api安全):

同时在产品中心->开发配置页面,将支付域名配置好:

这里不像微信小程序,小程序只能允许https协议接口,而扫码支付域名既支持https也支持http,非常方便,同时注意域名必须是一个备案域名。

至此,微信支付的前置操作就搞定了,下面我们来编写后台接口wx_pay.py,首先导入依赖的库和一些工具方法:

import requests
from django.http import HttpResponse, HttpResponseRedirect

import random
import time
import hashlib

import qrcode
from bs4 import BeautifulSoup

def trans_xml_to_dict(data_xml):
    soup = BeautifulSoup(data_xml, features='xml')
    xml = soup.find('xml')  # 解析XML
    if not xml:
        return {}
    data_dict = dict([(item.name, item.text) for item in xml.find_all()])
    return data_dict

def trans_dict_to_xml(data_dict):  # 定义字典转XML的函数
    data_xml = []
    for k in sorted(data_dict.keys()):  # 遍历字典排序后的key
        v = data_dict.get(k)  # 取出字典中key对应的value
        if k == 'detail' and not v.startswith(''.format(v)
        data_xml.append('<{key}>{value}'.format(key=k, value=v))
    return '{}'.format(''.join(data_xml))  # 返回XML

def get_sign(data_dict, key):  # 签名函数,参数为签名的数据和密钥
    params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=False)  # 参数字典倒排序为列表
    params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key
    # 组织参数字符串并在末尾添加商户交易密钥
    md5 = hashlib.md5()  # 使用MD5加密模式
    md5.update(params_str.encode())  # 将参数字符串传入
    sign = md5.hexdigest().upper()  # 完成加密并转为大写
    return sign

qrcode模块用来生成二维码,bs4模块用来将微信接口返回的xml解析成json,在21世纪的第二十个年头,微信接口居然还在使用原始的xml,这种反人类行为实在不能理解。

接下来我们来编写支付逻辑,参考微信官方文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5&index=3

业务流程说明:

(1)商户后台系统根据用户选购的商品生成订单。

(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;

(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。

(4)商户后台系统根据返回的code_url生成二维码。

(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。

(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。

(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。

(8)微信支付系统根据用户授权完成支付交易。

(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。

(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。

(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。

(12)商户确认订单已支付后给用户发货。

一望而知,我们需要调用微信的统一下单接口,文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

编写逻辑:

def wx_pay(request):

    url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'  # 微信扫码支付接口
    key = '945bec********a8fbf7d7'  #商户api秘钥
    total_fee = 1 #支付金额,单位分
    body = '123123'  # 商品描述
    out_trade_no = 'order_%s' % random.randrange(100000, 999999)  # 订单编号
    params = {
        'appid': 'wx09*****f',  # APPID
        'mch_id': '16****08',  # 商户号
        'notify_url': 'http://wxpay.v3u.cn/wx_back/',  # 支付域名回调地址
        'product_id': 'goods_%s' % random.randrange(100000, 999999),  # 商品编号
        'trade_type': 'NATIVE',  # 支付类型(扫码支付)
        'spbill_create_ip': '114.254.176.137',  # 发送请求服务器的IP地址
        'total_fee': total_fee,  # 订单总金额
        'out_trade_no': out_trade_no,  # 订单编号
        'body': body,  # 商品描述
        'nonce_str': 'ibuaiVcKdpRxkhJA'  # 字符串
    }
    sign = get_sign(params, key)  # 获取签名
    params.setdefault('sign', sign)  # 添加签名到参数字典
    xml = trans_dict_to_xml(params)  # 转换字典为XML
    response = requests.request('post', url, data=xml)  # 以POST方式向微信公众平台服务器发起请求
    data_dict = trans_xml_to_dict(response.content)  # 将请求返回的数据转为字典
    print(data_dict)
    qrcode_name = out_trade_no + '.png'  # 支付二维码图片保存路径
    if data_dict.get('return_code') == 'SUCCESS':  # 如果请求成功
        img = qrcode.make(data_dict.get('code_url'))  # 创建支付二维码片
        img.save('./' + qrcode_name)  # 保存支付二维码
    return HttpResponse(qrcode_name)

随后配置路由:

from myapp.wx_pay import wx_pay
from django.contrib.staticfiles.urls import staticfiles_urlpatterns

# ... the rest of your URLconf goes here ...
urlpatterns = [
    #定义超链接路由
    re_path('^static/upload/(?P.*)#39;,serve,{'document_root':'/static/upload/'}),
    path('wx_pay/', wx_pay),
]

启动django服务:

python manage.py runserver

访问http://localhost:8000/wx_pay/

没有问题,查看后台日志:

{'return_code': 'SUCCESS', 'return_msg': 'OK', 'appid': 'wx092344a76b9979ff', 'mch_id': '1602932608', 'nonce_str': 'bnJwGlXZ3eDSNgjs', 'sign': '2D81402DABEDF75E9A58F200FE7B6775', 'result_code': 'SUCCESS', 'prepay_id': 'wx1816114416896958d6f84177bd71da0000', 'trade_type': 'NATIVE', 'code_url': 'weixin://wxpay/bizpayurl?pr=JgBYgTS00'}

可以看到已经下单成功,不过订单状态处于预支付状态,同时检查二维码图片是否生成:

至此,后台逻辑基本搞定,下面就是如何在前端进行调用,同时让用户进行扫描操作,编写wx_pay.vue组件:





当用户点击按钮之后,旋即请求后端支付接口,将接口生成的二维码返回给前端,效果是这样的:

随后使用微信扫一扫功能进行扫码支付,需要注意的是,该二维码有效期只有五分钟,所以最好加上刷新功能。

支付成功之后,我们还需要对交易进行确认,所以根据微信官方文档,调用统一查询接口:

https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_2,根据接口文档编写逻辑:

def wx_check(request):

    #统一订单查询接口

    url = "https://api.mch.weixin.qq.com/pay/orderquery"

    out_trade_no = "order_537236" #支付后的商户订单号
    key = '945b******d7'  # 商户api密钥

    params = {
        'appid': 'wx0*****ff',  # APPID
        'mch_id': '16*****08',  # 商户号
        'out_trade_no': out_trade_no,  # 订单编号
        'nonce_str': 'ibuaiVcKdpRxkhJA'  # 随机字符串
    }
    sign = get_sign(params, key)  # 获取签名
    params.setdefault('sign', sign)  # 添加签名到参数字典
    xml = trans_dict_to_xml(params)  # 转换字典为XML
    response = requests.request('post', url, data=xml)  # 以POST方式向微信公众平台服务器发起请求
    data_dict = trans_xml_to_dict(response.content)  # 将请求返回的数据转为字典
    print(data_dict)

    return HttpResponse('ok')

这里需要注意的是,查询的订单编号可以使商户自己的订单编号,也可以是微信订单号,二者必取其一:

访问接口 http://localhost:8000/wx_check/

返回结果:

{'return_code': 'SUCCESS', 'return_msg': 'OK', 'appid': 'wx092344a76b9979ff', 'mch_id': '1602932608', 'nonce_str': 'BVoaDmxxADkpSFEl', 'sign': '23A86EB406B743E0C2C61C7E78DC9373', 'result_code': 'SUCCESS', 'openid': 'oy9q36f9Dpeokj9FWyN3j0znpIqE', 'is_subscribe': 'N', 'trade_type': 'NATIVE', 'bank_type': 'OTHERS', 'total_fee': '1', 'fee_type': 'CNY', 'transaction_id': '4200000806202012174121934231', 'out_trade_no': 'order_537236', 'attach': ' ', 'time_end': '20201217231553', 'trade_state': 'SUCCESS', 'cash_fee': '1', 'trade_state_desc': '支付成功', 'cash_fee_type': 'CNY'}

可以看到没有问题,但是由于涉及金钱业务,为了养成良好的测试习惯,最好登录商户后台再次确认:

结语:至此,整个微信扫码支付流程全部跑通,流程上比微信小程序支付逻辑要简单一些,同时由于不需要在线用户的openid,所以像微信小程序获取不到openid这样的大坑并不存在,后续会分享一些关于微信扫码订单退款的逻辑,搞笑的是,统一下单和查询接口没有并发限制,而申请退款居然有qps上的限制,所以退款流程应该会需要消息队列的介入。

相关阅读

  • 北京:在重点商圈组织开展外摆试点

  • 近日,北京市发改委、北京市商务局联合印发了《清理隐性壁垒优化消费营商环境实施方案》。方案提出51项改革任务打通痛点堵点,其中包括在重点商圈组织开展外摆试点,由区政府统
  • 数“智”化助力一键遥控送电

  • 东至县供电公司在35kV青山变10kV东阳125线叶桥02支线志德23支线ZK23开关遥控合闸成功,线路运行情况正常。1月10日晚19时35分,随着FTU遥控合闸成功,首次完成配网遥控送电工作,同
  • 南阳市人防办:优化流程提效益

  • 河南日报客户端记者 曾倩 通讯员 汪存林 唐迪为进一步提升服务质量,1月10日上午,南阳市行政审批服务中心人防“窗口”参加了行政审批服务全流程培训。会上,工改平台技术人员紧
  • 陕西:“三聚焦三优化” 畅通利企便民路

  • 2022年以来,陕西省人社系统紧紧围绕“三聚焦三优化”,对重大政策实施和高频事项经办进行全流程“复检”。截至目前,全省人社系统累计开展“走流程”459次,收集问题清单355条、需
  • 广阳区提速行政审批及政务服务

  • 今年以来,广阳区行政审批局不断优化服务流程、规范审批行为、创新服务方式,持续打造“办事不求人,服务在身边”的政务服务品牌,全面提速行政审批及政务服务。深化工程建设项目改

热门文章

  • OPPO k1的低价高配真实么?网友:不看不知道

  • 近日OPPO一款新机OPPO k1,摒弃了高价低配,就连自家老大哥r17都要怼一下。更是放弃了请代言人,以往的OPPO手机还没出来,各路流量小生,花样美男的代言就先来了。还有线下销售人员的
  • 一招教你手机无限制成为一台新设备

  • 大家平时用手机去注册app,肯定会遇到检测设备异常,交易关闭,等问题 这个都是手机已经不止1-2次注册过此app,不断更换手机仅是一个暂时的方法,却不是长久之计,手机总归会用完
  • 从零开始如何开网店

  • 随着互联网的高速发展,人们的生活发生了翻天覆地的变化,生活节奏越来越快,网购已经成为家家户户生活中离不开的一种购物方式了。网购的发展使得越来越多的人想要涉足电商事业,那

最新文章

  • Win10基于Vue.js+Django+Python3微信扫码支付流程

  • 之前的一篇文章:mpvue1.0+python3.7+Django2.0.4实现微信小程序的支付功能,主要介绍了微信小程序内部支付的流程,然而实际上微信小程序有一定的局限性,也就是用户范围仅限于小程
  • 新春开工第一天 企业复工忙生产

  •   人勤春来早,奋进正当时。1月28日,春节假期后,东港区各企业乘着全市绿色低碳高质量发展攻坚突破动员大会的东风,抢抓时间、开足马力,陆续恢复生产。尽管是年后上班的第一天,但
  • 数字科技与数字经济的数字大脑模型

  • 作者:刘锋本文2022年10月发表于中国科学报社《科学新闻》杂志21世纪是数字科技和数字经济爆发的时代。从2000年开始,社交网络、web2.0等数字科技不断涌现,由此诞生的谷歌、亚马