(二十六)微信小程序支付流程

小程序支付官网

统一下单API官网

再次签名

小程序前端页面

<radio-group bindchange="changeGoods">
  <view class='row'wx:for="{{goodList}}" wx:key="index">
    <text>{{item.title}}-{{item.price}}</text>
    <radio class="radio" value="{{item.id}}"></radio>
  </view>
</radio-group>


<button bindtap="doBuy">购买</button>
const app = getApp()

Page({
  data: {
  goodList:null,
  selectId:null
  },
  /**
   * 你选着那件商品就知道是哪个id   
   */
  changeGoods:function(e){
    this.setData({
      selectId: e.detail.value
    })
  },
 /**
  * 一启动就展示商品列表
  */
  onLoad: function () {
   wx.request({
     url: 'http://127.0.0.1:8000/goods/',
     method: 'GET',
     dataType: 'json',
     responseType: 'text',
     success: (res) =>{
       console.log(res)
       this.setData({
         goodList:res.data
       })
     },
   })
  },
})

// 先写一部分  
doBuy: function () {
    // 向后台发送一个请求,生成一大堆数据
    wx.request({
      url: 'http://127.0.0.1:8000/payment/',
      data: {
      goodId:this.data.selectId
      },
      method: 'POST',
      dataType: 'json',
      responseType: 'text',
      success: (res)=> {
        console.log(res)
      },
    })

    // 获取这一大堆数据,然后弹出支付二维码
  },

后端

  url(r'^payment/', payment.PaymentView.as_view()),
# 根据上面 微信小程序官网提供的文档 
from
app01 import models from rest_framework.generics import ListAPIView from rest_framework.views import APIView import random from rest_framework import serializers from rest_framework.response import Response from xml.etree import ElementTree as ET # 操作xml import requests import time def md5(string): import hashlib m = hashlib.md5() m.update(string.encode('utf-8')) return m.hexdigest() class PaymentView(APIView): def post(self, request, *args, **kwargs): goods_id = request.data.get('goodId') '''模拟的订单号和用户''' order_random = str(int(time.time())) user_obj = models.UserInfo.objects.filter(id=1).first() # 有openid goods_object = models.Goods.objects.filter(id=goods_id).first() # 商品价格 models.Order.objects.create(goods=goods_object,user=user_obj,uid=order_random,status=1) # 生成一大堆数据 按照微信规则---官方文档 '''https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1''' # ###################### 1.调用支付统一下单 ###################### info = { 'appid': '', # 小程序id 'mch_id': '', # 商户号 'device_info': '', # 设备号 'nonce_str': "".join([chr(random.randint(65, 90)) for _ in range(12)]), 'sign_type': "MD5", # 加密类型 'body': "保证金", # 'detail': '这是一个商品详细描述信息.', 'attach': '微信小程序', 'out_trade_no': order_random, # 订单id 'total_fee': goods_object.price, # 总金额 'spbill_create_ip': request.META.get('REMOTE_ADDR'), # 终端里的ip # 终端IP(用户IP) remote_addr = request.META.get('REMOTE_ADDR') 'notify_url': "http://1.1.1.1:8012/pay/notify/", # 支付成功之后,微信异步通知 待会要用 'trade_type': 'JSAPI', 'openid': user_obj.openid # openid } # 1.1 签名 '''https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3''' # 对字典中的key按照ASCII码从小到大排序 # 将排完序的值拼接 stringA = appid=wx55cca0b94f723dc7&mch_id=1526049051 # 让stringA和key拼接:stringSignTemp = stringA+"&key=192006250b4c09247ec02edce69f6a2d" key为商户平台设置的密钥key # MD5(stringSignTemp) # 将密文转换为大写 # 得到签名 sign # 把签名再添加到info中 info['sign'] = sign值 pay_key = "2SzCvaKgYExuItWBfYAqJFs72uUleD14" # 商户的key temp = "&".join(["{0}={1}".format(k, info[k]) for k in sorted(info)] + ["{0}={1}".format("key", pay_key, ), ]) sign = md5(temp).upper() info['sign'] = sign # 1.2 向 https://api.mch.weixin.qq.com/pay/unifiedorder 发请求 (json转换为xml) xml_string = "<xml>{0}</xml>".format("".join(["<{0}>{1}</{0}>".format(k, v) for k, v in info.items()])) prepay = requests.post('https://api.mch.weixin.qq.com/pay/unifiedorder',data=xml_string.encode('utf-8')) # 1.3 从结果xml中提取 prepay_id # from xml.etree import ElementTree as ET root = ET.XML(prepay.content.decode('utf-8')) prepay_dict = {child.tag:child.text for child in root} prepay_id = prepay_dict['prepay_id'] # ####################### 2.再次签名 ####################### info_dict = { 'appId': "wx2a313db1501c7253", 'timeStamp': str(int(time.time())), # 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间 'nonceStr': "".join([chr(random.randint(65, 90)) for _ in range(12)]), # 随机字符串,长度为32个字符以下。 'package': 'prepay_id={0}'.format(prepay_id), # 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* 'signType': 'MD5', # 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致 } temp = "&".join( ["{0}={1}".format(k, info_dict[k]) for k in sorted(info_dict)] + ["{0}={1}".format("key", pay_key, ), ]) sign2 = md5(temp).upper() info_dict['paySign'] = sign2 return Response(info_dict)

在回到前端

doBuy: function () {
    // 向后台发送一个请求,生成一大堆数据
    wx.request({
      url: 'http://127.0.0.1:8000/payment/',
      data: {
      goodId:this.data.selectId
      },
      method: 'POST',
      dataType: 'json',
      responseType: 'text',
      success: (res)=> {
        console.log(res.data)
        // 获取这一大堆数据,然后弹出支付二维码
        wx.requestPayment(
          {
            'timeStamp': res.data.timeStamp,
            'nonceStr': res.data.nonceStr,
            'package': res.data.package,
            'signType': 'MD5',
            'paySign': res.data.paySign,
            'success': function (res) { 
                // 要是成功了 就往上面info里的notify_url发请求
            },
            'fail': function (res) { 

            },
            'complete': function (res) { 

            }
          })
      },
    })

notify_url发请求 就是告知我们的ip地址------结合info里的地址

url(r'^notify/', payment.NotifyView.as_view()),
class NotifyView(APIView):
    '''支付完后的通知'''
    def post(self, request, *args, **kwargs):
        # 1. 腾讯会发一个XML格式的数据  获取结果把结果XML转换为字典格式
        root = ET.XML(request.body.decode('utf-8'))
        # 变json数据
        result = {child.tag: child.text for child in root}

        # 2. 校验签名是否正确,防止恶意请求。
        sign = result.pop('sign')


        key = "key为商户平台设置的密钥key"
        temp = "&".join(
            ["{0}={1}".format(k, result[k]) for k in sorted(result)] + ["{0}={1}".format("key", key, ), ])
        local_sign = md5(temp).upper()

        # 签名一致
        if local_sign == sign:
            # 拿到订单号
            out_trade_no = result.get('out_trade_no')
            # 根据订单号,把数据库的订单状态修改为支付成功
            models.Order.objects.filter(uid=out_trade_no).update(status=2)
            response = """<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>"""
            return Response(response)
原文地址:https://www.cnblogs.com/a438842265/p/12509981.html