zoukankan      html  css  js  c++  java
  • 小程序支付

    小程序支付流程

    1. 用户发起请求下单支付
    2. 我们要保证用是登入状态。
    3. 组织数据,请求统一下单接口,微信官方会同步返回一个prepay_id
    4. 重新组织数据,进行签名,将重新组织的数据返回给小程序,小程序在吊起支付
    5. 用户就可以进行支付,支付结果会同步返回给小程序
    6. 后台修改订单支付状态是通过微信官方服务器的异步通知

    官方文档业务流程

    wxml

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

    js

    // pages/test3/test3.js
    const app = getApp()
    Page({
    
      pay:function(){
        wx.request({
          url: app.globalData.baseurl+"pay/",
          data:{"money":1,token:wx.getStorageSync('token')},
          method:"POST",
          success (e) {
            console.log("支付数据",e)
            wx.requestPayment(
              {
              'timeStamp':e.data.data.timeStamp,
              'nonceStr': e.data.data.nonceStr,
              'package': e.data.data.package,
              'signType': e.data.data.signType,
              'paySign': e.data.data.paySign,
              'success':function(res){
                console.log("成功",res)
              },
              'fail':function(res){
                console.log("失败",res)
              },
              
              })
          }
    
        })
      }
    })
    

    views.py

    from rest_framework.views import  APIView
    from rest_framework.response import  Response
    from django.core.cache import cache
    from app01.wx import settings
    import hashlib,requests,time
    
    class Pay(APIView):
        def post(self,request):
            param = request.data
            if param.get("token") and param.get("money"):
                openid_session_key = cache.get(param.get("token"))
                if openid_session_key:
                    # 获取客户端ip,如果是负载均衡,就用HTTP_X_FORWARDED_FOR,如果不是就用下面的
                    # nginx 转发:--》访问是nginx,->nginx -> uwsgi
                    if request.META.get('HTTP_X_FORWARDED_FOR'):
                        #有负载均衡就用这个
                        self.ip = request.META['HTTP_X_FORWARDED_FOR']
                    else:
                        #没有负载均衡就用这个
                        self.ip = request.META['REMOTE_ADDR']
                    self.openid =openid_session_key.split("&")[1]
                    self.money =param.get("money")
                    data = self.get_pay_data()
                    return  Response({"code":0,"msg":"ok","data":data})
    
                else:
                    return Response({"code": 2, "msg": "token无效"})
            else:
                return  Response({"code":1,"msg":"缺少参数"})
    
        def get_nonce_str(self):
            import random
            data = "123456789abcdefghijklmn"
            nonce_str = "".join(random.sample(data,10))
            #random.sample(从哪里取,取多小个),变成列表
            return  nonce_str
    
        def get_order_id(self):
            import time
            import random
            data = "123456789abcdefghijklmn"
            order_no = str(time.strftime("%Y%m%d%H%M%S"))+"".join(random.sample(data, 5))
            return  order_no
    
        def get_sign(self):
            data_dict ={
            "appid" :  self.appid,
            "mch_id":self.mch_id,
            "nonce_str" : self.nonce_str,
            "body" :  self.body,
            "out_trade_no" : self.out_trade_no,
            "total_fee" : self.total_fee,
            "spbill_create_ip" : self.ip,
            "notify_url" : self.notify_url,
            "trade_type" :  self.trade_type,
            "openid" : self.openid,
            }
            sign_str = "&".join([f"{k}={data_dict[k]}"  for k in sorted(data_dict)])
            sign_str = f"{sign_str}&key={settings.pay_apikey}"
            print("sign_str", sign_str)
            md5 = hashlib.md5()
            md5.update(sign_str.encode("utf-8"))
            sign = md5.hexdigest()
            return  sign.upper()
    
    
        def xml_to_dict(self,xml_data):
            import xml.etree.ElementTree as ET
    
            xml_dict ={}
    
            root = ET.fromstring(xml_data)
    
            for child in root:
                xml_dict[child.tag]= child.text
            return  xml_dict
    
    
        def get_two_sign(self,data):
            data_dict = {
                "appId":settings.AppId,
                "timeStamp":str(int(time.time())),
                "nonceStr":data['nonce_str'],
                "package":f"prepay_id={data['prepay_id']}",
                "signType":"MD5"
    
            }
            sign_str = "&".join([f"{k}={data_dict[k]}" for k in sorted(data_dict)])
            sign_str = f"{sign_str}&key={settings.pay_apikey}"
            md5 = hashlib.md5()
            md5.update(sign_str.encode("utf-8"))
            sign = md5.hexdigest()
            return sign.upper() , data_dict['timeStamp']
    
    
        def get_pay_data(self):
            self.appid = settings.AppId
            self.mch_id = settings.pay_mchid
            self.nonce_str = self.get_nonce_str()
            self.body = "老男孩学费"
            self.out_trade_no = self.get_order_id()
            self.total_fee =self.money
            self.spbill_create_ip =self.ip
            self.notify_url = "htttp://www.test.com"
            self.trade_type ="JSAPI"
            self.openid = self.openid
            self.sign = self.get_sign()
    
            body_data = f'''
            <xml>
                <appid>{self.appid}</appid>
                <mch_id>{self.mch_id}</mch_id>
                <nonce_str>{self.nonce_str}</nonce_str>
                <body>{self.body}</body>
                <out_trade_no>{self.out_trade_no}</out_trade_no>
                <total_fee>{self.total_fee}</total_fee>
                <spbill_create_ip>{self.spbill_create_ip}</spbill_create_ip>
                <notify_url>{self.notify_url}</notify_url>
                <trade_type>{self.trade_type }</trade_type>
                <openid>{self.openid }</openid>      
                <sign>{self.sign}</sign>      
            </xml> 
            '''
            url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
            # 如果发送的xml数据要把数据转化二进制。body_data.encode("utf-8")
            # request
            response = requests.post(url,data=body_data.encode("utf-8"),headers = {"content-type":"application/xml"} )
            #接收一个二进制的响应
            data_dict = self.xml_to_dict(response.content)
            pay_sign,timeStamp = self.get_two_sign(data_dict)
            data = {
    
                "timeStamp": timeStamp,
                "nonceStr": data_dict['nonce_str'],
                "package": f"prepay_id={data_dict['prepay_id']}",
                "signType": "MD5",
                "paySign":pay_sign
            }
            return data
    
    
    

    xml解析模块

    <xml>
      <appid name="属性值" >{.child.text}</appid>
       child.tag表示appid   
    </xml> 
    
    import xml.etree.ElementTree as ET
    
    如果我们要解析一个xml文件
    tree = ET.parse('country_data.xml')
    root = tree.getroot()
    
    如果解析字符串
    root = ET.fromstring(country_data_as_string)
    
    这个root是 Element 
    for child in root:
    	 print(child.tag, child.attrib)
    	 #child.tag表是标签名,child.attrib表示获取属性
    	 #child.text就表示获取内容
    
    

    小程序支付总结

    1 接收到支付请求。我们先组织数据,然后进行统一下单前的签名
    - 请求的数据与响应的数据都是xml.请求的时候,xml数据要变成二进制,heards中的content-type:"application/xml"
    -响应的数据也是xml,我要用xml.etree.ElementTree将他转化为字典
    2 拿到统一下单数据,最重要的prepay_id,进行再次签名。把一下数据发送给小程序。
    			"timeStamp": 时间戳
                "nonceStr":随机字符串
                "package": f"prepay_id={data_dict['prepay_id']}",统一下单中的到的prepay_id
                "signType": "MD5",
                "paySign":通过上面数据进行加密的结果
     3 小程序掉用wx.resquestPayment()吊起支付
    

    以后再遇支付文档

    1 统一下单
    签名:80%。
    签名方式没有搞懂。用了哪些数据,传过去的数据,和签名的数据不一致。
    appid = 123 传过去,appid =456
    appid 123  --->apid
    
    每一个数据的类型,长短,意义是什么?一定要搞清楚,
    2异步回调
    
  • 相关阅读:
    HTML 基本知识
    Vue.js 基本内容
    机器学习概述
    9 验证回文串
    c 字符串的一些常用函数
    8 有效的字母异位词
    7 字符串中的第一个唯一字符
    对公平锁、非公平锁、可重入锁、递归锁、自旋锁的理解
    一个解释volatile关键字最好的例子
    Singleton多种实现方式的在多线程情况下的优缺点
  • 原文地址:https://www.cnblogs.com/kai-/p/12488918.html
Copyright © 2011-2022 走看看