小程序支付功能
詳細流程步驟請看官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
xcx.wxml
<button bindtap="pay">支付</button>
xcx.js
const app=getApp()
pay: function () {
wx.request({
url: app.globalData.URL + 'pay/',
data: {
token: wx.getStorageSync("token")
},
header: {
"content-type": "application/json"
},
method: "POST",
success: function (e) {
console.log("pay_data", e)
wx.requestPayment(
{
'timeStamp': e.data.data.timeStamp,
'nonceStr': e.data.data.nonceStr,
'package': e.data.data.package,
'signType': 'MD5',
'paySign': e.data.data.paySign,
'success': function (res) {
console.log("支付成功", res)
},
'fail': function (res) {
console.log("支付失敗", res)
}
})
}
})
}
app.js
globalData: {
userInfo: null,
URL:"http://127.0.0.1:8000/",
}
后台業務(重點)
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
#path('admin/', admin.site.urls),
#path('login/', views.LoginAPIView.as_view()),
#path('userinfo/', views.UserInfo.as_view()),
path('pay/', views.Pay.as_view()),
]
app01/wx/settings.py
# 小程序 appid
AppId="wx10658d6b326fd700"
# 小程序 appsecret
AppSecret="43cae8cf58c13b2323afef1f8d3c054b"
# 調用的微信后端接口
code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
# 商戶號
pay_mchid ='1415981402'
pay_apikey = 'xi34nu5jn7x2uujd8u4jiijd2u5d6j8e'
views.py---(由於商戶號(mch_id)及pay_apikey需要申請或公司提供,所有本段代碼無法本地運行驗證)
class Pay(APIView):
def post(self, request):
# print(111111)
param = request.data
# 獲取前台傳入的token
if param.get("token"):
# 檢驗token 拿到緩存數據庫中的 session_key與openid做綁定得到的 val
cache_data = cache.get(param.get("token"))
if cache_data:
# 獲取客戶端ip,如果是負載均衡,就用HTTP_X_FORWARDED_FOR,如果不是就用下面的
# 通過 requests.META接口 向微信后端 獲取參數 ip
if request.META.get('HTTP_X_FORWARDED_FOR'):
self.ip = request.META['HTTP_X_FORWARDED_FOR']
else:
self.ip = request.META['REMOTE_ADDR']
session_key, self.openid = cache_data.split("&")
# 獲取所有返回參數 重點就是(prepay_id)
data = self.get_pay_data()
return Response({"code": 200, "msg": "suc", "data": data})
else:
return Response({"code": 202, "msg": "token無效"})
# 獲取參數nonce_str 隨機字符串
def get_nonce_str(self, num=30):
# strs = ""
# for i in range(30):
# strs += str(random.randint(0,9)) 產生結果是一個列表
all_str = "0123456789abcdefghijklmnopqrstuvwxyz"
# 將列表內的所有字符串以''拼接得到一個字符串
strs = "".join(random.sample(all_str, num))
return strs
# 獲取參數out_trade_no
def get_out_trade_no(self):
import time
strs = str(int(time.time())) + self.get_nonce_str(5)
return strs
# 獲取參數 簽名 sign
def get_sign(self):
data_dic = {
"nonce_str": self.nonce_str,
"out_trade_no": self.out_trade_no,
"spbill_create_ip": self.ip,
"notify_url": self.notify_url,
"openid": self.openid,
"body": self.body,
"trade_type": "JSAPI",
"sign_type": "MD5",
"appid": self.appid,
"total_fee": self.total_fee,
"mch_id": self.mch_id
}
# 對數據進行排序(sorted)並拼接成需求格式
# sorted 是對 字典中的 key排序 key1, key2, key3, ...
str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
str_b = f"{str_a}&key={settings.pay_apikey}"
md5 = hashlib.md5()
md5.update(str_b.encode("utf8"))
return md5.hexdigest().upper()
# 將 xml 數據轉換成 字典
def xml_to_dic(self, xml_data):
# 導入 xml
import xml.etree.ElementTree as ET
xml_data = ET.fromstring(xml_data)
dic = {}
for child in xml_data:
dic[child.tag] = child.text
return dic
# 獲取 prepay_id
def get_prepay_data(self):
url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
response = requests.post(url=url, data=self.body_data.encode("utf8"),
headers={"content-type": "application/xml"})
xml_data = response.content
dic_data = self.xml_to_dic(xml_data)
return dic_data
# 二次簽名
def get_second_sign(self):
self.second_nonceStr = self.get_nonce_str()
self.timeStamp = str(int(time.time()))
data_dic = {
"appId": settings.AppId,
"timeStamp": self.timeStamp,
"nonceStr": self.second_nonceStr,
"package": f"prepay_id={self.prepay_data.get('prepay_id')}",
"signType": "MD5"
}
print(data_dic)
str_a = "&".join([f"{i}={data_dic[i]}" for i in sorted(data_dic)])
str_b = f"{str_a}&key={settings.pay_apikey}"
md5 = hashlib.md5()
md5.update(str_b.encode("utf8"))
return md5.hexdigest().upper()
# 支付功能 ,返回數據 data
def get_pay_data(self):
self.appid = settings.AppId
self.mch_id = settings.pay_mchid
self.nonce_str = self.get_nonce_str()
self.sign_type = "MD5"
self.body = "py11最難一屆"
self.out_trade_no = self.get_out_trade_no()
self.total_fee = 1
self.spbill_create_ip = self.ip
self.notify_url = "http://www.weixin.qq.com/wxpay/pay.php"
self.trade_type = "JSAPI"
self.sign = self.get_sign()
self.body_data = f"""
<xml>
<appid>{self.appid}</appid>
<mch_id>{self.mch_id}</mch_id>
<nonce_str>{self.nonce_str}</nonce_str>
<sign>{self.sign}</sign>
<body>{self.body}</body>
<out_trade_no>{self.out_trade_no}</out_trade_no>
<total_fee>1</total_fee>
<sign_type>MD5</sign_type>
<spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
<notify_url>{self.notify_url}</notify_url>
<openid>{self.openid}</openid>
<trade_type>JSAPI</trade_type>
</xml>"""
self.prepay_data = self.get_prepay_data()
second_sign = self.get_second_sign()
data = {
"timeStamp": self.timeStamp,
"nonceStr": self.second_nonceStr,
"package": f"prepay_id={self.prepay_data.get('prepay_id')}",
"paySign": second_sign
}
return data