微信小程序支付
1.微信支付的流程大致分为四步骤:
1.在小程序中获取用户的登录信息,成功后可以获取到用户的code值
2.在用户自己的服务端请求微信获取用户openid接口,成功后可以获取用户的openid值
3.在用户自己的服务器上面请求微信的统一下单接口,下单成功后可以获取prepay_id值
4.在微信小程序中支付订单,最终实现微信的支付功能
https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
具体的流程图如下所示:
2.关键代码
2.1 获取用户的信息,也就是小程序中的登录接口:
小程序代码部分
onGetOpenId(){
var that = this
var wxcode = ''
//调用微信API获取wxcode
wx.login({
success:function(res)
{
console.log('loginCode:', res.code)
wxcode = res.code
//调用后端API获取appid
that.$http.get('/getappid/'+wxcode)
.then(function(res){
console.log(res)
var openid = res.data.openid
var session_key = res.data.session_key
})
.catch(function(error){
console.log('获取openid失败1')
return fail
})
}
});
},
后端代码部分(使用PYTHON)
APPID = 'XXX'
SECRET = 'XXX'
class WxApi(Resource):
def get(self, wxcode):
print('wxcode=', wxcode)
r = requests.get(
'https://api.weixin.qq.com/sns/jscode2session?appid={}&secret=XXXX&js_code={}&grant_type=authorization_code'
.format(APPID,SECRET,wxcode))
print('openid={} session_key={}'.format(r.json()['openid'],
r.json()['session_key']))
return {
'message': 'success',
'session_key': r.json()['session_key'],
'openid': r.json()['openid']
}
api.add_resource(WxApi, '/api/getappid/<wxcode>')
2.2 调用微信接口获取prepayid
前端代码部分
onSubmitClick:function(){
//访问后端服务部分
that.$http.post('/prepayid',{
'openid':that.GLOBAL.openid,
'spbill_create_ip':myip,
'total_fee':that.g_tprice,
})
.then(function(res){
console.log('获取prepayid返回')
console.log(res)
console.log(res.data.data.package)
//调用微信支付接口
wx.requestPayment(
{
'timeStamp': res.data.data.timeStamp,
'nonceStr':res.data.data.nonceStr,
'package': res.data.data.package,
'signType': res.data.data.signType,
'paySign': res.data.data.paySign,
'success':function(res){
console.log(res)
},
'fail':function(res){},
'complete':function(res){}
})
})
.catch(function(res){
console.log('获取prepayid error返回')
console.log(res)
})
}
后端代码部分
import datetime, os, re
import requests
import hashlib
from time import strftime, strptime, mktime, time
import random
import xmltodict
import string
APPID = 'xxxx'
MCHID = 'xxxxx'
KEY = 'xxxxxx'
NOTIFY_URL = 'xxxxx'
# 生成32位随机数
def generate_nonce_str():
ran_str = ''.join(random.sample(string.ascii_letters + string.digits, 32))
return ran_str
# 生成签名
def generate_sign(param):
stringA = ''
print('param={}'.format(param))
ks = sorted(param.keys())
print('ks={}'.format(ks))
# 参数排序
for k in ks:
print('k={} param[k]={}'.format(k, param[k]))
stringA += (k + '=' + str(param[k]) + '&')
print(stringA)
# 拼接商户KEY
stringSignTemp = stringA + "key=" + KEY
print('stringSignTemp={}'.format(stringSignTemp))
# md5加密
hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))
sign = hash_md5.hexdigest().upper()
return sign
def trans_dict_to_xml(data):
"""
将 dict 对象转换成微信支付交互所需的 XML 格式数据
:param data: dict 对象
:return: xml 格式数据
"""
xml = []
for k in data.keys():
v = data.get(k)
v = '<![CDATA[{}]]>'.format(v)
xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
return '<xml>{}</xml>'.format(''.join(xml))
# 发送xml请求
def send_xml_request(url, param):
# dict 2 xml
# param = {'root': param}
xml = trans_dict_to_xml(param)
print('xml = {}'.format(xml))
response = requests.post(
url, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
print('send success')
# xml 2 dict
msg = response.text
xmlmsg = xmltodict.parse(msg)
print('xmlmsg={}'.format(xmlmsg))
return xmlmsg
# 调用微信小程序统一下单api
def generate_bill(out_trade_no, fee, openid):
url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
rnonce_str = generate_nonce_str()
# 1. 参数
param = {
"appid": APPID,
"mch_id": MCHID, # 商户号
"nonce_str": rnonce_str, # 随机字符串
"body": 'TEST_pay', # 支付说明
"out_trade_no": out_trade_no, # 自己生成的订单号
"total_fee": fee,
"spbill_create_ip": '127.0.0.1', # 发起统一下单的ip
"notify_url": NOTIFY_URL,
"trade_type": 'JSAPI', # 小程序写JSAPI
"openid": openid,
}
# 2. 获取数字签名
sign = generate_sign(param)
param["sign"] = sign # 加入签名
print('param sigin={}'.format(param))
# 3. 调用接口
xmlmsg = send_xml_request(url, param)
# 4. 获取prepay_id
if xmlmsg['xml']['return_code'] == 'SUCCESS':
if xmlmsg['xml']['result_code'] == 'SUCCESS':
prepay_id = xmlmsg['xml']['prepay_id']
# 时间戳
timeStamp = str(int(time()))
# 5. 五个参数
data = {
"appId": APPID,
"nonceStr": rnonce_str,
"package": "prepay_id=" + prepay_id,
"signType": 'MD5',
"timeStamp": timeStamp,
}
print('data = {}'.format(data))
# 6. paySign签名
paySign = generate_sign(data)
data["paySign"] = paySign # 加入签名
# 7. 传给前端的签名后的参数
return data
class WxPrepay_idApi(Resource):
"""
获取微信小程序支付
"""
def post(self):
args = parse.parse_args()
openid = args['openid']
total_fee = args['total_fee']
spbill_create_ip = args['spbill_create_ip']
out_trade_no = generate_id('wxapp')
print('openid={} total_fee={}'.format(openid, total_fee))
data = generate_bill(openid=openid, out_trade_no=out_trade_no, fee=10)
return {'message': 'success', 'data': data}
api.add_resource(WxPrepay_idApi, '/api/prepayid')