本文詳細講解Python語言進行公眾號開發時,參考開發者文檔進行JSAPI支付,並給出具體的代碼:
一、開發流程
業務流程說明:
1、商戶server調用統一下單接口請求訂單,api參見公共api【統一下單API】
2、商戶server接收支付通知,api參見公共api【支付結果通知API】
3、商戶server查詢支付結果,api參見公共api【查詢訂單API】
二.具體代碼
1.需准備的參數
import time import json import hashlib from random import Random import requests from django.http import HttpResponse notify_url = "....../wx_result_js/" # 回調函數,完整路由,服務器要帶上域名,對應的視圖是下面4中的回調函數 trade_type = 'JSAPI' # 交易方式 APP_ID = "wx......" # 公眾賬號的appid MCH_ID = "......" # 商戶號 API_KEY = "......" # 微信商戶平台(pay.weixin.qq.com) -->賬戶設置 -->API安全 -->密鑰設置,設置完成后把密鑰復制到這里 UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 該url是微信下單api CREATE_IP = '......' # 服務器IP
2.調用支付接口
def wx_pay_js(request): # data = json.loads(request.body) # print(request.body) total_price = 0.01 # 訂單總價 order_name = '商品費用' # 訂單名字 order_detail = '商品費用' # 訂單描述 order_id = 20200411234567 # 自定義的訂單號 openid = "......" # 用戶的openid,在這種類型中支付必傳 data_dict = wxpay_js(order_id, order_name, order_detail, total_price, openid) # 如果請求成功 if data_dict.get('return_code') == 'SUCCESS': prepay_id = data_dict.get('prepay_id', "") nonce_str = data_dict.get('nonce_str', "") data = {} # 前端需要這些參數才能調用微信支付頁面 data['appId'] = APP_ID data['timeStamp'] = int(time.time()) # 必填,生成簽名的時間戳 data['nonceStr'] = nonce_str data['package'] = "prepay_id=" + prepay_id data['signType'] = "MD5" # 添加簽名加密類型 sign = get_sign(data, API_KEY) # 獲取簽名 data['paySign'] = sign # 添加簽名到參數字典 if prepay_id: s = { "code": 1000, "msg": "獲取成功", "data": data } s = json.dumps(s, ensure_ascii=False) return HttpResponse(s) s = { "code": 1001, "msg": "獲取失敗", "data": "" } s = json.dumps(s, ensure_ascii=False) return HttpResponse(s)
3.前端調用方法
function onBridgeReady(){ WeixinJSBridge.invoke( 'getBrandWCPayRequest', { "appId":"wx2421b1c4370ec43b", //公眾號名稱,由商戶傳入 "timeStamp":"1395712654", //時間戳,自1970年以來的秒數 "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //隨機串 "package":"prepay_id=u802345jgfjsdfgsdg888", "signType":"MD5", //微信簽名方式: "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信簽名 }, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ){ // 使用以上方式判斷前端返回,微信團隊鄭重提示: //res.err_msg將在用戶支付成功后返回ok,但並不保證它絕對可靠。 } }); } if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady); } }else{ onBridgeReady(); }
4.支付后回調接口
def wx_result_js(request): data_dict = trans_xml_to_dict(request.body) # 回調數據轉字典 print('支付回調結果', data_dict) sign = data_dict.pop('sign') # 取出簽名 back_sign = get_sign(data_dict, API_KEY) # 計算簽名 # 驗證簽名是否與回調簽名相同 if sign == back_sign and data_dict['return_code'] == 'SUCCESS': order_no = data_dict['out_trade_no'] print('微信支付成功會回調!') # 處理支付成功邏輯,根據訂單號修改后台數據庫狀態 # 返回接收結果給微信,否則微信會每隔8分鍾發送post請求 return HttpResponse(trans_dict_to_xml({'return_code': 'SUCCESS', 'return_msg': 'OK'})) return HttpResponse(trans_dict_to_xml({'return_code': 'FAIL', 'return_msg': 'SIGNERROR'}))
5.工具函數
def random_str(randomlength=8): """ 生成隨機字符串 :param randomlength: 字符串長度 :return: """ strs = '' chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789' length = len(chars) - 1 random = Random() for i in range(randomlength): strs += chars[random.randint(0, length)] print(strs) return strs # 請求統一支付接口,多一個openid,JSAPI方式請求時必須帶上這個openid參數 def wxpay_js(order_id, order_name, order_price_detail, order_total_price, openid=''): nonce_str = random_str() # 拼接出隨機的字符串即可,我這里是用 時間+隨機數字+5個隨機字母 total_fee = int(float(order_total_price) * 100) # 付款金額,單位是分,必須是整數 print(total_fee) params = { 'appid': APP_ID, # APPID 'mch_id': MCH_ID, # 商戶號 'nonce_str': nonce_str, # 隨機字符串 'out_trade_no': order_id, # 訂單編號,可自定義 'total_fee': total_fee, # 訂單總金額 'spbill_create_ip': CREATE_IP, # 自己服務器的IP地址 'notify_url': notify_url, # 回調地址,微信支付成功后會回調這個url,告知商戶支付結果 'body': order_name, # 商品描述 'detail': order_price_detail, # 商品描述 'trade_type': trade_type, # 掃碼支付類型 'openid': openid } sign = get_sign(params, API_KEY) # 獲取簽名 params['sign'] = sign # 添加簽名到參數字典 xml = trans_dict_to_xml(params) # 轉換字典為XML response = requests.request('post', UFDODER_URL, data=xml.encode()) # 以POST方式向微信公眾平台服務器發起請求 data_dict = trans_xml_to_dict(response.content) # 將請求返回的數據轉為字典 print(data_dict) return data_dict def get_sign(data_dict, key): """ 簽名函數 :param data_dict: 需要簽名的參數,格式為字典 :param key: 密鑰 ,即上面的API_KEY :return: 字符串 """ params_list = sorted(data_dict.items(), key=lambda e: e[0], reverse=False) # 參數字典倒排序為列表 params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + key # 組織參數字符串並在末尾添加商戶交易密鑰 md5 = hashlib.md5() # 使用MD5加密模式 md5.update(params_str.encode('utf-8')) # 將參數字符串傳入 sign = md5.hexdigest().upper() # 完成加密並轉為大寫 print(sign) return sign def trans_dict_to_xml(data_dict): """ 定義字典轉XML的函數 :param data_dict: :return: """ data_xml = [] for k in sorted(data_dict.keys()): # 遍歷字典排序后的key v = data_dict.get(k) # 取出字典中key對應的value if k == 'detail' and not v.startswith('<![CDATA['): # 添加XML標記 v = '<![CDATA[{}]]>'.format(v) data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v)) return '<xml>{}</xml>'.format(''.join(data_xml)) # 返回XML def trans_xml_to_dict(data_xml): """ 定義XML轉字典的函數 :param data_xml: :return: """ data_dict = {} try: import xml.etree.cElementTree as ET except ImportError: import xml.etree.ElementTree as ET root = ET.fromstring(data_xml) for child in root: data_dict[child.tag] = child.text return data_dict
總結
按照上面五步走,一定可以將JSAPI方式的支付做成功,具體的業務邏輯需要自己處理一下即可,
希望能夠提高大家的開發效率,如有不足請多多指教。

作者:
E-QUAL
出處: https://www.cnblogs.com/liujiajia_me/
本文版權歸作者和博客園共有,不得轉載,未經作者同意參考時必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
出處: https://www.cnblogs.com/liujiajia_me/
本文版權歸作者和博客園共有,不得轉載,未經作者同意參考時必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
本文內容參考如下網絡文獻得來,用於個人學習,如有侵權,請您告知刪除修改。