小程序支付
一、总结
1 小程序的登入
1 先调用wx.login来获取code.
2 将code通过wx.request传递到后端。
后端通过code,appid,Appsecret来请求code2session接口来获得
openid,session_key,openid是单个应用用户的唯一标识
3 后端得到open_id与session_key,进行存储,并自定义登入状态,key->val,val是openid与session_key,key相当于token,在把token传递给小程序。
4 小程序收到后端返回的token,保存,下次请求后端的时候如果需要登入状态,把这个token带上
2 授权
1 微信的部分需要用户同意后才能使用,哪些接口需要用户同意呢?我们scope列表中的对应关系。
2 我们可以用wx.getSetting来判断接口有没有被用户授权,查看哪个接口,就需要判断wx.getSetting的返回值,authsetting中的socop值判断。
3 如果我们发现这个接口的authsetting中的scope为false,就标识该用户没有对该接口授权,
这个时候我们就可以用wx.authorize吊起对应授权弹框,如果要对哪个接口授权,就需要给wx.authorize,传递对应的scope值,如果
authsetting中的scope为true,表示该用户已经对该接口授权,我们就可以直接使用对应的接口
4 wx.authorize不能将wx.getUserInfor这接口直接吊起授权弹框。我们只能通过<button>按钮的行式手动吊起弹框
二、以后看支付文档
1 统一下单
签名:80%。
签名方式没有搞懂。用了哪些数据,传过去的数据,和签名的数据不一致。
appid = 123 传过去,appid =456
appid 123 --->apid
每一个数据的类型,长短,意义是什么?一定要搞清楚,
2异步回调



三、支付
1、搜支付文档




小程序业务流程

接口

统一下单接口

接上的xml数据

xml的返回结果

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 用户发起请求下单支付
2 我们要保证用是登入状态。
3 组织数据,请求统一下单接口,微信官方会同步返回一个prepay_id
4 重新组织数据,进行签名,将重新组织的数据返回给小程序,小程序在吊起支付。
5 用户就可以进行支付,支付结果会同步返回给小程序
6 后台修改订单支付状态是通过微信官方服务器的异步通知
四 、支付实现 代码
前端
test3.wxml写个支付按钮
// pages/test3/test3.js const app = getApp() Page({ /*页面的初始数据 */ data: { }, click:function() { wx.navigateBack({ delta:2 }) }, 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) }, }) }
后端

pay.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
# 随机产生订单id 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()
# 把xml转化成字典 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
小程序支付案例总结
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()吊起支付
。

浙公网安备 33010602011771号