Django1.11配合uni-app發(fā)起微信支付!
經(jīng)過(guò)三天的斷斷續(xù)續(xù)的奮戰(zhàn),我終于是干動(dòng)了微信支付。愛(ài)掏網(wǎng) - it200.com為了以后不忘記,現(xiàn)在來(lái)一篇教程,來(lái)來(lái)來(lái),開(kāi)干!!!
一、準(zhǔn)備階段
1、準(zhǔn)備階段我們需要去微信官網(wǎng)申請(qǐng)一個(gè)小程序或者公眾號(hào)。愛(ài)掏網(wǎng) - it200.com獲得AppID和AppSecret。愛(ài)掏網(wǎng) - it200.com
2、去微信商戶(hù)平臺(tái) 成為商家,開(kāi)通JSAPI用來(lái)獲得商戶(hù)號(hào)和自己配置的鑰匙。愛(ài)掏網(wǎng) - it200.com然后再商戶(hù)平臺(tái)上面綁定小程序appid。愛(ài)掏網(wǎng) - it200.com
(點(diǎn)擊下面圖片進(jìn)入官方鏈接!)
在配置里面配置一個(gè)自己的key,需要記住后臺(tái)開(kāi)發(fā)的時(shí)候需要!
關(guān)聯(lián)后即可在小程序管理頁(yè)面開(kāi)通微信支付!
到此,準(zhǔn)備階段完成!
二、梳理流程
在這里我大概寫(xiě)一下流程:首先我們?cè)谇岸税l(fā)起微信登陸,此時(shí)微信會(huì)給我們返回一個(gè)openid,這個(gè)openid一定要留存在某一個(gè)位置。愛(ài)掏網(wǎng) - it200.com然后前段發(fā)起微信支付,向后端發(fā)送數(shù)據(jù)請(qǐng)求,后端對(duì)結(jié)合前段的數(shù)據(jù)向微信方面發(fā)送一個(gè)請(qǐng)求,請(qǐng)求相關(guān)數(shù)據(jù),得到相關(guān)數(shù)據(jù)之后把數(shù)據(jù)發(fā)送給前段,前段收到數(shù)據(jù),利用微信接口再向微信指定連接發(fā)送請(qǐng)求,微信返回請(qǐng)求,即可!這個(gè)就是全流程,很多人肯定已經(jīng)懵了。愛(ài)掏網(wǎng) - it200.com沒(méi)事,咱一步一步來(lái),別步子跨大了——扯到蛋了!
以上就是數(shù)據(jù)處理階段大概流程!
三、代碼實(shí)現(xiàn)
0、用戶(hù)登錄根據(jù)用戶(hù)code獲取openid
uni.login({ provider: 'weixin', success: function(loginRes) { let code = loginRes.code; if (!_this.isCanUse) { //非第一次授權(quán)獲取用戶(hù)信息 uni.getUserInfo({ provider: 'weixin', success: function(infoRes) { //獲取用戶(hù)信息后向調(diào)用信息更新方法 _this.nickName = infoRes.userInfo.nickName; //昵稱(chēng) _this.avatarUrl = infoRes.userInfo.avatarUrl; //頭像 _this.updateUserInfo();//調(diào)用更新信息方法 } }); } //2.將用戶(hù)登錄code傳遞到后臺(tái)置換用戶(hù)SessionKey、OpenId等信息 uni.request({ url: 'http://127.0.0.1:8000/users/', data: { code: code, }, method: 'GET', header: { 'content-type': 'application/json' }, success: (res) => { console.log(res.data) if ( res.data.state== 1001) { console.log("新注冊(cè)的用戶(hù)!") _this.OpenId = res.data.openid; } else{ _this.OpenId = res.data.openid; console.log("注冊(cè)過(guò)的用戶(hù)!開(kāi)始設(shè)置本地緩存!") console.log(res.data[0].id) if ( res.data[0].id ) { //這里獲得登陸狀態(tài),然后根據(jù)登陸狀態(tài)來(lái)改變用戶(hù)按鈕信息!!!! } else{ }; _this.user_id = res.data[0].id uni.setStorage({ key: 'user', data: res.data, success: function () { console.log('設(shè)置緩存成功'); } }); // _this.gotoshopping() // uni.reLaunch({//信息更新成功后跳轉(zhuǎn)到小程序首頁(yè) // url: '/pages/shopping/shopping' // }); } //openId、或SessionKdy存儲(chǔ)//隱藏loading uni.hideLoading(); } }); }, });
if request.GET.get("code"): ret = {"state": 1000} code = request.GET.get("code") url = "https://api.weixin.qq.com/sns/jscode2session" appid = "xxxxxxxxxxxxx" secret = "xxxxxxxxxxxxxxxxxxxxx" # url一定要拼接,不可用傳參方式 url = url + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code" import requests r = requests.get(url) print("======", r.json()) openid = r.json()['openid'] user = users.objects.filter(openid=openid).all() if not user: ret["state"] = 1001 ret["msg"] = "用戶(hù)第一次登陸" ret["openid"] = openid return Response(ret) else: serializer = self.get_serializer(user, many=True) return Response(serializer.data)
1、首先需要?jiǎng)?chuàng)建一個(gè)confige.py的配置文件!然后寫(xiě)路由,讓前端找到“門(mén)”在哪里!
config.py
# 微信支付的配置參數(shù) client_appid = 'xxxxxxxxxxxxxx' # 小程序appid client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx' # 小程序secret Mch_id = 'xxxxxxxxxxx' # 商戶(hù)號(hào) Mch_key = 'xxxxxxxxxxxxxxxxxxx' # 商戶(hù)Key order_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder' # 訂單地址
url.py
router = routers.DefaultRouter() router.register("users", views.UsersViewSet) router.register("goods", views.GoodsViewSet) router.register("comments", views.CommentsViewSet) router.register("payOrder", views.OrdersViewSet) #這個(gè)就是微信支付的接口 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'', include(router.urls)), ]+ static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
view.py
class OrdersViewSet(viewsets.ModelViewSet): queryset = Order.objects.all() serializer_class = OrderModelSerializer def create(self, request, *args, **kwargs): if request.data.get("user_id"): from goods.wxpay.wxpay import payOrder data = payOrder(request) print(data) return Response(data) else: serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
2、然后創(chuàng)建邏輯文件,獲取數(shù)據(jù)請(qǐng)求數(shù)據(jù)返回?cái)?shù)據(jù)!
wxpay.py
# -*- coding: utf-8 -*- from .config import client_appid, client_secret, Mch_id, Mch_key, order_url import hashlib import datetime import xml.etree.ElementTree as ET import requests from ..models import users # 生成簽名的函數(shù) 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' } print(ret) # 處理函數(shù),對(duì)參數(shù)按照key=value的格式,并按照參數(shù)名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() print(sign.upper()) return sign.upper() # 生成隨機(jī)字符串 def getNonceStr(): import random data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP" nonce_str = ''.join(random.sample(data, 30)) return nonce_str # 生成商品訂單號(hào) def getWxPayOrdrID(): date = datetime.datetime.now() # 根據(jù)當(dāng)前系統(tǒng)時(shí)間來(lái)生成商品訂單號(hào)。愛(ài)掏網(wǎng) - it200.com時(shí)間精確到微秒 payOrdrID = date.strftime("%Y%m%d%H%M%S%f") return payOrdrID # 獲取全部參數(shù)信息,封裝成xml def get_bodyData(openid, client_ip, price): body = 'Mytest' # 商品描述 notify_url = 'https://127.0.0.1:8000/payOrder/' # 支付成功的回調(diào)地址 可訪問(wèn) 不帶參數(shù) nonce_str = getNonceStr() # 隨機(jī)字符串 out_trade_no = getWxPayOrdrID() # 商戶(hù)訂單號(hào) total_fee = str(price) # 訂單價(jià)格 單位是 分 # 獲取簽名 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 += ' ' return bodyData def xml_to_dict(xml_data): ''' xml to dict :param xml_data: :return: ''' xml_dict = {} root = ET.fromstring(xml_data) for child in root: xml_dict[child.tag] = child.text return xml_dict def dict_to_xml(dict_data): ''' dict to xml :param dict_data: :return: ''' xml = ["' + Mch_id + ' ' # 商戶(hù)號(hào) bodyData += '' + nonce_str + ' ' # 隨機(jī)字符串 bodyData += '' + notify_url + ' ' # 支付成功的回調(diào)地址 bodyData += '' + openid + ' ' # 用戶(hù)標(biāo)識(shí) bodyData += '' + out_trade_no + ' ' # 商戶(hù)訂單號(hào) bodyData += '' + client_ip + ' ' # 客戶(hù)端終端IP bodyData += '' + total_fee + ' ' # 總金額 單位為分 bodyData += 'JSAPI ' # 交易類(lèi)型 小程序取值如下:JSAPI bodyData += '' + sign + ' ' bodyData += '"] for k, v in dict_data.iteritems(): xml.append("{1}{0}>".format(k, v)) xml.append(" ") return "".join(xml) # 獲取返回給小程序的paySign def get_paysign(prepay_id, timeStamp, nonceStr): pay_data = { 'appId': client_appid, 'nonceStr': nonceStr, 'package': "prepay_id=" + prepay_id, 'signType': 'MD5', 'timeStamp': timeStamp } stringA = '&'.join(["{0}={1}".format(k, pay_data.get(k)) for k in sorted(pay_data)]) stringSignTemp = '{0}&key={1}'.format(stringA, Mch_key) sign = hashlib.md5(stringSignTemp.encode("utf-8")).hexdigest() return sign.upper() # 統(tǒng)一下單支付接口 def payOrder(request): import time # 獲取價(jià)格,和用戶(hù)是誰(shuí) price = request.data.get("price") user_id = request.data.get("user_id") # 獲取客戶(hù)端ip client_ip, port = request.get_host().split(":") # 獲取小程序openid openid = users.objects.get(id=user_id).openid # 請(qǐng)求微信的url url = order_url # 拿到封裝好的xml數(shù)據(jù) body_data = get_bodyData(openid, client_ip, price) # 獲取時(shí)間戳 timeStamp = str(int(time.time())) # 請(qǐng)求微信接口下單 respOne= requests.post(url, body_data.encode("utf-8"), headers={'Content-Type': 'application/xml'}) # 回復(fù)數(shù)據(jù)為xml,將其轉(zhuǎn)為字典 cOntent= xml_to_dict(respone.content) print(content) # 返回給調(diào)用函數(shù)的數(shù)據(jù) ret = {"state": 1000} if content["return_code"] == 'SUCCESS': # 獲取預(yù)支付交易會(huì)話標(biāo)識(shí) prepay_id = content.get("prepay_id") # 獲取隨機(jī)字符串 nOnceStr= content.get("nonce_str") # 獲取paySign簽名,這個(gè)需要我們根據(jù)拿到的prepay_id和nonceStr進(jìn)行計(jì)算簽名 paySign = get_paysign(prepay_id, timeStamp, nonceStr) # 封裝返回給前端的數(shù)據(jù) data = {"prepay_id": prepay_id, "nonceStr": nonceStr, "paySign": paySign, "timeStamp": timeStamp} print('=========',data) ret["msg"] = "成功" return data else: ret["state"] = 1001 ret["msg"] = "失敗" return ret
3、前段獲取后端返回的數(shù)據(jù)給微信再次發(fā)送數(shù)據(jù)請(qǐng)求!(包含點(diǎn)擊的時(shí)候往后端發(fā)送數(shù)據(jù)處理請(qǐng)求)
pay(){ uni.request({ url: 'http://127.0.0.1:8000/payOrder/', method: 'POST', header: { 'content-type': 'application/json' }, data: { user_id:this.user_id, price:128 }, success: res => { console.log("success") console.log(res.data) uni.requestPayment({ provider: 'wxpay', timeStamp: res.data.timeStamp, nonceStr: res.data.nonceStr, package: 'prepay_id='+String(res.data.prepay_id), signType: 'MD5', paySign: res.data.paySign, success: function (res) { console.log('success:' + JSON.stringify(res)); // 支付成功,給后臺(tái)發(fā)送數(shù)據(jù),保存訂單 }, fail: function (err) { console.log('fail:' + JSON.stringify(err)); // 支付失敗,給后臺(tái)發(fā)送數(shù)據(jù),保存訂單 } }); }, fail: (res) => { console.log("fail") console.log(res) }, complete: () => {} }); }
至此相信大家也就會(huì)了。愛(ài)掏網(wǎng) - it200.com
附上我的目錄結(jié)構(gòu)
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持。愛(ài)掏網(wǎng) - it200.com