• 小程序的支付功能实现


    小程序支付功能

    详细流程步骤请看官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3

    xcx.wxml

    <button bindtap="pay">支付</button>
    

    xcx.js

    const app=getApp()
    pay: function () {
        wx.request({
          url: app.globalData.URL + 'pay/',
          data: {
            token: wx.getStorageSync("token")
          },
          header: {
            "content-type": "application/json"
          },
          method: "POST",
          success: function (e) {
            console.log("pay_data", e)
            wx.requestPayment(
              {
                'timeStamp': e.data.data.timeStamp,
                'nonceStr': e.data.data.nonceStr,
                'package': e.data.data.package,
                'signType': 'MD5',
                'paySign': e.data.data.paySign,
                'success': function (res) {
                  console.log("支付成功", res)
                },
                'fail': function (res) {
                  console.log("支付失败", res)
                }
              })
          }
        })
      }
    
    

    app.js

    globalData: {
        userInfo: null,
        URL:"http://127.0.0.1:8000/",
      }
    

    后台业务(重点)

    urls.py

    from django.contrib import admin
    from django.urls import path
    from app01 import views
    urlpatterns = [
        #path('admin/', admin.site.urls),
        #path('login/', views.LoginAPIView.as_view()),
        #path('userinfo/', views.UserInfo.as_view()),
        path('pay/', views.Pay.as_view()),
    ]
    

    app01/wx/settings.py

    # 小程序 appid
    AppId="wx10658d6b326fd700"
    
    # 小程序 appsecret
    AppSecret="43cae8cf58c13b2323afef1f8d3c054b"
    
    # 调用的微信后端接口
    code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
    
    # 商户号
    pay_mchid ='1415981402'
    pay_apikey = 'xi34nu5jn7x2uujd8u4jiijd2u5d6j8e'
    

    views.py---(由于商户号(mch_id)及pay_apikey需要申请或公司提供,所有本段代码无法本地运行验证)

    class Pay(APIView):
        def post(self, request):
            # print(111111)
            param = request.data
            # 获取前台传入的token
            if param.get("token"):
                # 检验token 拿到缓存数据库中的 session_key与openid做绑定得到的 val
                cache_data = cache.get(param.get("token"))
                if cache_data:
                    # 获取客户端ip,如果是负载均衡,就用HTTP_X_FORWARDED_FOR,如果不是就用下面的		
                    # 通过 requests.META接口 向微信后端 获取参数 ip
                    if request.META.get('HTTP_X_FORWARDED_FOR'):
                        self.ip = request.META['HTTP_X_FORWARDED_FOR']
                    else:
                        self.ip = request.META['REMOTE_ADDR']
                    session_key, self.openid = cache_data.split("&")
                    # 获取所有返回参数 重点就是(prepay_id)
                    data = self.get_pay_data()
                    return Response({"code": 200, "msg": "suc", "data": data})
                else:
                    return Response({"code": 202, "msg": "token无效"})
    	# 获取参数nonce_str 随机字符串
        def get_nonce_str(self, num=30):
            # strs = ""
            # for i in range(30):
            #     strs += str(random.randint(0,9))  产生结果是一个列表
            all_str = "0123456789abcdefghijklmnopqrstuvwxyz"
            # 将列表内的所有字符串以''拼接得到一个字符串
            strs = "".join(random.sample(all_str, num)) 
            return strs
    	# 获取参数out_trade_no
        def get_out_trade_no(self):
            import time
            strs = str(int(time.time())) + self.get_nonce_str(5)
            return strs
    	# 获取参数 签名 sign
        def get_sign(self):
            data_dic = {
                "nonce_str": self.nonce_str,
                "out_trade_no": self.out_trade_no,
                "spbill_create_ip": self.ip,
                "notify_url": self.notify_url,
                "openid": self.openid,
                "body": self.body,
                "trade_type": "JSAPI",
                "sign_type": "MD5",
                "appid": self.appid,
                "total_fee": self.total_fee,
                "mch_id": self.mch_id
            }
            # 对数据进行排序(sorted)并拼接成需求格式
            # sorted 是对 字典中的 key排序 key1, key2, key3, ...
            str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
            str_b = f"{str_a}&key={settings.pay_apikey}"
            md5 = hashlib.md5()
            md5.update(str_b.encode("utf8"))
            return md5.hexdigest().upper()
    	# 将 xml 数据转换成 字典
        def xml_to_dic(self, xml_data):
            # 导入 xml 
            import xml.etree.ElementTree as ET
            xml_data = ET.fromstring(xml_data)
            dic = {}
            for child in xml_data:
                dic[child.tag] = child.text
            return dic
    	# 获取 prepay_id
        def get_prepay_data(self):
            url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
            response = requests.post(url=url, data=self.body_data.encode("utf8"),
            headers={"content-type": "application/xml"})
            xml_data = response.content
            dic_data = self.xml_to_dic(xml_data)
            return dic_data
    	# 二次签名 
        def get_second_sign(self):
            self.second_nonceStr = self.get_nonce_str()
            self.timeStamp = str(int(time.time()))
            data_dic = {
                "appId": settings.AppId,
                "timeStamp": self.timeStamp,
                "nonceStr": self.second_nonceStr,
                "package": f"prepay_id={self.prepay_data.get('prepay_id')}",
                "signType": "MD5"
            }
            print(data_dic)
            str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
            str_b = f"{str_a}&key={settings.pay_apikey}"
            md5 = hashlib.md5()
            md5.update(str_b.encode("utf8"))
            return md5.hexdigest().upper()
    	# 支付功能 ,返回数据 data
        def get_pay_data(self):
            self.appid = settings.AppId
            self.mch_id = settings.pay_mchid
            self.nonce_str = self.get_nonce_str()
            self.sign_type = "MD5"
            self.body = "py11最难一届"
            self.out_trade_no = self.get_out_trade_no()
            self.total_fee = 1
            self.spbill_create_ip = self.ip
            self.notify_url = "http://www.weixin.qq.com/wxpay/pay.php"
            self.trade_type = "JSAPI"
            self.sign = self.get_sign()
            self.body_data = f"""
                    <xml>
                    <appid>{self.appid}</appid>
                    <mch_id>{self.mch_id}</mch_id>
                    <nonce_str>{self.nonce_str}</nonce_str>
                    <sign>{self.sign}</sign>
                    <body>{self.body}</body>
                    <out_trade_no>{self.out_trade_no}</out_trade_no>
                    <total_fee>1</total_fee>
                    <sign_type>MD5</sign_type>
                    <spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
                    <notify_url>{self.notify_url}</notify_url>
                    <openid>{self.openid}</openid>
                    <trade_type>JSAPI</trade_type> 
                    </xml>"""
            self.prepay_data = self.get_prepay_data()
    
            second_sign = self.get_second_sign()
            data = {
                "timeStamp": self.timeStamp,
                "nonceStr": self.second_nonceStr,
                "package": f"prepay_id={self.prepay_data.get('prepay_id')}",
                "paySign": second_sign
            }
            return data
    
  • 相关阅读:
    hadoop学习摘要
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。
    sqlserver 2012 IDE中 Windows身份验证连接服务器报错 ,Login failed for user 'xxxAdministrator'. 原因: 找不到与提供的名称匹配的登录名。
    不重复随机数列生成算法
    异步和等待(async和await)
    mvc和mvvm的区别?
    Redis命令大全
    Java NIO 三大组件之 Buffer
    Java NIO 三大组件之 Channel
    Java NIO概述
  • 原文地址:https://www.cnblogs.com/chmily/p/12055221.html
Copyright © 2020-2023  润新知