原文转载自「刘悦的技术博客」https://v3u.cn/a_id_112

其实微信支付有很多种形式,刷脸,扫码,APP支付,小程序支付等,这边只说明小程序支付的实现,不过原理上都大同小异。

首先,需要注册微信公众号平台https://mp.weixin.qq.com,并且开通微信支付功能,随后将你的小程序关联一个微信商户:pay.weixin.qq.com,这一系列申请下来之后,你手中需要有微信小程序appid,微信小程序秘钥,商户号,以及商户秘钥,这四个关键的支付配置变量。

然后大体流程分两步:

1 在自己的后台服务器上访问微信提供的接口,拿到预支付交易会话标识prepay_id、微信返回的随机字符串nonce_str,这两个参数是要返回给自己的小程序的,小程序在调起微信支付接口时需要这两个参数。

2 小程序拿到后台传递的参数,需要后台传递5个参数,timeStamp,nonceStr,package,signType,paySign。然后在小程序上调起支付接口时传递我们拿到的参数,就可以完成支付。

先构造后台接口,这里我们使用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 = ''

bodyData += '' + client_appid + '' # 小程序ID

bodyData += '' + body + '

' #商品描述

bodyData += '' + Mch_id + '' #商户号

bodyData += '' + nonce_str + '' #随机字符串

bodyData += '' + notify_url + '' #支付成功的回调地址

bodyData += '' + openid + '' #用户标识

bodyData += '' + out_trade_no + ''#商户订单号

bodyData += '' + client_ip + ''#客户端终端IP

bodyData += '' + total_fee + '' #总金额 单位为分

bodyData += 'JSAPI' #交易类型 小程序取值如下:JSAPI

bodyData += '' + sign + ''

bodyData += ''

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)

}

})

}

})

}

需要注意的是,请求后台接口时,openid和price是必须要传递的,openid是微信小程序当前用户的唯一标识,而price是价格,单位是分

最后,完成了支付,没什么难的,有一些地方需要提醒:后台接口如果需要在本地调试的话,只能用127.0.0.1这种ip的形式,微信不支持localhost,另外需要xmltodict这个三方库将微信统一支付接口返回的xml转成dict,话说都什么年代了,微信接口居然还在使用xml。

附上代码:

后端django:https://gitee.com/QiHanXiBei/mydjango

前端mpvue:https://gitee.com/QiHanXiBei/mpvue

原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_112

推荐阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。