微信小程序的支付功能简单讲解
微信小程序的支付功能简单讲解
官方文档 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
大体流程分为两步
- 在自己的后台服务器上访问微信提供的接口,拿到预支付交易会话标识prepay_id、微信返回的随机字符串nonce_str,这两个参数是要返回给自己的小程序的,小程序在调起微信支付接口时需要这两个参数。
- 小程序拿到后台传递的参数,需要后台传递5个参数,timeStamp,nonceStr,package,signType,paySign。然后在小程序上调起支付接口时传递我们拿到的参数,就可以完成支付。
首先当然需要你有微信支付的资质,支付账户什么的,去申请开通。
如果不熟悉xml的可以看这篇博客或文档,往里面填东西就好
django后台微信支付
from django.shortcuts import render
#导包
from django.http import HttpResponse,HttpResponseRedirect,JsonResponse
#导入类视图
from django.views import View
import requests
import hashlib
import xmltodict
client_appid = \'你的小程序appid\'
Mch_id = \'你的商户编号\'
Mch_key = \'商户交易秘钥\'
def myindex(request):
return HttpResponse(\'这里是首页\')
def myback(request):
return HttpResponse(\'这里是回调网址\')
def get_nonce_str():
import uuid
return str(uuid.uuid4()).replace(\'-\', \'\')
def getWxPayOrdrID():
import datetime
date=datetime.datetime.now()
#根据当前系统时间来生成商品订单号。时间精确到微秒
payOrdrID=date.strftime("%Y%m%d%H%M%S%f")
return payOrdrID
#生成签名的函数
def paysign(appid,body,mch_id,nonce_str,notify_url,openid,out_trade_no,spbill_create_ip,total_fee):
ret= {
"appid": appid,
"body": body,
"mch_id": mch_id,
"nonce_str": nonce_str,
"notify_url":notify_url,
"openid":openid,
"out_trade_no":out_trade_no,
"spbill_create_ip":spbill_create_ip,
"total_fee":total_fee,
"trade_type": \'JSAPI\'
}
#处理函数,对参数按照key=value的格式,并按照参数名ASCII字典序排序
stringA = \'&\'.join(["{0}={1}".format(k, ret.get(k))for k in sorted(ret)])
stringSignTemp = \'{0}&key={1}\'.format(stringA,Mch_key)
sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest()
return sign.upper()
def generate_sign(param):
\'\'\'生成签名\'\'\'
stringA = \'\'
ks = sorted(param.keys())
print(param)
# 参数排序
for k in ks:
stringA += (k + \'=\' + param[k] + \'&\')
# 拼接商户KEY
stringSignTemp = stringA + "key=" + Mch_key
# md5加密,也可以用其他方式
hash_md5 = hashlib.md5(stringSignTemp.encode(\'utf8\'))
sign = hash_md5.hexdigest().upper()
return sign
#获取全部参数信息,封装成xml,传递过来的openid和客户端ip,和价格需要我们自己获取传递进来
def get_bodyData(openid,client_ip,price):
body = \'Mytest\' #商品描述
notify_url = \'http://localhost:8000/back\' #填写支付成功的回调地址,微信确认支付成功会访问这个接口
nonce_str =get_nonce_str() #随机字符串
out_trade_no =getWxPayOrdrID() #商户订单号
total_fee =str(price) #订单价格,单位是 分
#获取签名
sign=paysign(client_appid,body,Mch_id,nonce_str,notify_url,openid,out_trade_no,client_ip,total_fee)
bodyData = \'<xml>\'
bodyData += \'<appid>\' + client_appid + \'</appid>\' # 小程序ID
bodyData += \'<body>\' + body + \'</body>\' #商品描述
bodyData += \'<mch_id>\' + Mch_id + \'</mch_id>\' #商户号
bodyData += \'<nonce_str>\' + nonce_str + \'</nonce_str>\' #随机字符串
bodyData += \'<notify_url>\' + notify_url + \'</notify_url>\' #支付成功的回调地址
bodyData += \'<openid>\' + openid + \'</openid>\' #用户标识
bodyData += \'<out_trade_no>\' + out_trade_no + \'</out_trade_no>\'#商户订单号
bodyData += \'<spbill_create_ip>\' + client_ip + \'</spbill_create_ip>\'#客户端终端IP
bodyData += \'<total_fee>\' + total_fee + \'</total_fee>\' #总金额 单位为分
bodyData += \'<trade_type>JSAPI</trade_type>\' #交易类型 小程序取值如下:JSAPI
bodyData += \'<sign>\' + sign + \'</sign>\'
bodyData += \'</xml>\'
return bodyData
#统一下单支付接口
def payOrder(request):
import time
#获取价格 单位是分
price= int(request.GET.get("price",1))
#获取客户端ip
client_ip,port=request.get_host().split(":")
#获取小程序openid
#openid=\'of2Fa5C2BNn77OOh1hfydxK4pVJc\'
openid = request.GET.get("openid")
#请求微信的url
url=\'https://api.mch.weixin.qq.com/pay/unifiedorder\'
#拿到封装好的xml数据
body_data=get_bodyData(openid,client_ip,price)
#获取时间戳
timeStamp=str(int(time.time()))
#请求微信接口下单
respone=requests.post(url,body_data.encode("utf-8"),headers={\'Content-Type\': \'application/xml\'})
print(respone.content)
#回复数据为xml,将其转为字典
content=xmltodict.parse(respone.content)
print(content)
return_code = content[\'xml\'][\'return_code\']
if return_code==\'SUCCESS\':
prepay_id = content[\'xml\'][\'prepay_id\']
# 时间戳
timeStamp = str(int(time.time()))
# 5. 五个参数
data = {
"appId":client_appid ,
"nonceStr": get_nonce_str(),
"package": "prepay_id=" + prepay_id,
"signType": \'MD5\',
"timeStamp": timeStamp,
}
# 6. paySign签名
paySign = generate_sign(data)
data["paySign"] = paySign # 加入签名
print(data)
# 7. 传给前端的签名后的参数
return JsonResponse(data,safe=False,json_dumps_params={\'ensure_ascii\':False})
else:
return HttpResponse("请求支付失败")
接下来在前端mpvue写支付请求逻辑,由前端请求后端的django统一支付接口,获取关键的五个变量,随后利用这五个变量,请求微信官网支付接口,完成支付逻辑
paytest(){
console.log(\'支付测试\');
console.log(this.userinfo.openid);
wx.request({
url: \'http://127.0.0.1:8000/pay/\',
header: {
\'content-type\': \'application/json\'
},
data: {\'openid\': this.userinfo.openid,\'price\': 1},
success: function (res) {
wx.requestPayment({
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: res.data.signType,
paySign: res.data.paySign,
\'success\': function (res) {
console.log(res)
},
\'fail\': function (res) {
console.log(res)
}
})
}
})
}
后台接口如果需要在本地调试的话,只能用127.0.0.1这种ip的形式,微信不支持localhost,另外需要xmltodict这个三方库将微信统一支付接口返回的xml转成dict。