Python實(shí)現(xiàn)微信小程序支付功能
正文
由于最近自己在做小程序的支付,就在這里簡(jiǎn)單介紹一下講一下用python做小程序支付這個(gè)流程。當(dāng)然在進(jìn)行開發(fā)之前還是建議讀一下具體的流程,清楚支付的過程。
1.支付交互流程
當(dāng)然具體的參數(shù)配置可以參考官方文檔https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1
2.獲取openid(微信用戶標(biāo)識(shí))
import requests from config import APPID, SECRET class OpenidUtils(object): def __init__(self, jscode): self.url = "https://api.weixin.qq.com/sns/jscode2session" self.appid = APPID # 小程序id self.secret = SECRET # 不要跟后面支付的key搞混 self.jscode = jscode # 前端傳回的動(dòng)態(tài)jscode def get_openid(self): # url一定要拼接,不可用傳參方式 url = self.url + "?appid=" + self.appid + "&secret=" + self.secret + "&js_code=" + self.jscode + "&grant_type=authorization_code" r = requests.get(url) print(r.json()) openid = r.json()['openid'] return openid
3.支付請(qǐng)求
# -*- coding:utf-8 -*-
import requests
import hashlib
import xmltodict
import time
import random
import string
import urllib2
import sys
class WX_PayToolUtil():
""" 微信支付工具 """
def __init__(self, APP_ID, MCH_ID, API_KEY, NOTIFY_URL):
self._APP_ID = APP_ID # 小程序ID
self._MCH_ID = MCH_ID # # 商戶號(hào)
self._API_KEY = API_KEY
self._UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder" # 接口鏈接
self._NOTIFY_URL = NOTIFY_URL # 異步通知
def generate_sign(self, param):
'''生成簽名'''
stringA = ''
ks = sorted(param.keys())
# 參數(shù)排序
for k in ks:
stringA += (k + '=' + param[k] + '&')
# 拼接商戶KEY
stringSignTemp = stringA + "key=" + self._API_KEY
# md5加密,也可以用其他方式
hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))
sign = hash_md5.hexdigest().upper()
return sign
'''
# python2另外一種實(shí)現(xiàn)方法
def generate_sign(self, params):
ret = []
for k in sorted(params.keys()):
if (k != 'sign') and (k != '') and (params[k] is not None):
ret.append('%s=%s' % (k, params[k]))
params_str = '&'.join(ret)
params_str = '%(params_str)s&key=%(partner_key)s' % {'params_str': params_str, 'partner_key': key}
reload(sys)
sys.setdefaultencoding('utf8')
params_str = hashlib.md5(params_str.encode('utf-8')).hexdigest()
sign = params_str.upper()
return sign
'''
def getPayUrl(self, orderid, openid, goodsPrice, **kwargs):
"""向微信支付端發(fā)出請(qǐng)求,獲取url"""
key = self._API_KEY
nonce_str = ''.join(random.sample(string.letters + string.digits, 30)) # 生成隨機(jī)字符串,小于32位
params = {
'appid': self._APP_ID, # 小程序ID
'mch_id': self._MCH_ID, # 商戶號(hào)
'nonce_str': nonce_str, # 隨機(jī)字符串
"body": '測(cè)試訂單', # 支付說明
'out_trade_no': orderid, # 生成的訂單號(hào)
'total_fee': str(goodsPrice), # 標(biāo)價(jià)金額
'spbill_create_ip': "127.0.0.1", # 小程序不能獲取客戶ip,web用socekt實(shí)現(xiàn)
'notify_url': self._NOTIFY_URL,
'trade_type': "JSAPI", # 支付類型
"openid": openid, # 用戶id
}
# 生成簽名
params['sign'] = self.generate_sign(params)
# python3一種寫法
param = {'root': params}
xml = xmltodict.unparse(param)
response = requests.post(self._UFDODER_URL, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
# xml 2 dict
msg = response.text
xmlmsg = xmltodict.parse(msg)
# 4. 獲取prepay_id
if xmlmsg['xml']['return_code'] == 'SUCCESS':
if xmlmsg['xml']['result_code'] == 'SUCCESS':
prepay_id = xmlmsg['xml']['prepay_id']
# 時(shí)間戳
timeStamp = str(int(time.time()))
# 5. 五個(gè)參數(shù)
data = {
"appId": self._APP_ID,
"nonceStr": nonce_str,
"package": "prepay_id=" + prepay_id,
"signType": 'MD5',
"timeStamp": timeStamp,
}
# 6. paySign簽名
paySign = self.generate_sign(data)
data["paySign"] = paySign # 加入簽名
# 7. 傳給前端的簽名后的參數(shù)
return data
# python2一種寫法
'''
request_xml_str = '<xml>'
for key, value in params.items():
if isinstance(value, str):
request_xml_str = '%s<%s><![CDATA[%s]]></%s>' % (request_xml_str, key, value, key,)
else:
request_xml_str = '%s<%s>%s</%s>' % (request_xml_str, key, value, key,)
request_xml_str = '%s</xml>' % request_xml_str
# 向微信支付發(fā)出請(qǐng)求,并提取回傳數(shù)據(jù)
res = urllib2.Request(self._UFDODER_URL, data=request_xml_str.encode("utf-8"))
res_data = urllib2.urlopen(res)
res_read = res_data.read()
doc = xmltodict.parse(res_read)
return_code = doc['xml']['return_code']
if return_code == "SUCCESS":
result_code = doc['xml']['result_code']
if result_code == "SUCCESS":
doc = doc['xml']
data = {
"appId": self._APP_ID,
"nonceStr": nonce_str,
"package": "prepay_id=" + doc["prepay_id"],
"signType": 'MD5',
"timeStamp": str(int(time.time())),
}
# paySign簽名
paySign = self.generate_sign(data)
data["paySign"] = paySign # 加入簽名
return data
else:
err_des = doc['xml']['err_code_des']
return err_des
else:
fail_des = doc['xml']['return_msg']
return fail_des
'''
當(dāng)然你可能會(huì)遇到的錯(cuò)誤有簽名錯(cuò)誤,一般的情況是你的appSecret和商戶號(hào)的API密鑰兩個(gè)弄錯(cuò)了,當(dāng)然如果不是還有可能是其他問題,解決方案鏈接 http://www.dhdzp.com/article/166176.htm 。
其他的支付方式獲取用戶的ip地址可以通過socket.gethostbyname(socket.gethostname())方法來獲取。
4.支付回調(diào)
# 統(tǒng)一下單回調(diào)處理
import xmltodict
from django.http import HttpResponse
def payback(request):
msg = request.body.decode('utf-8')
xmlmsg = xmltodict.parse(msg)
return_code = xmlmsg['xml']['return_code']
if return_code == 'FAIL':
# 官方發(fā)出錯(cuò)誤
return HttpResponse("""<xml><return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[Signature_Error]]></return_msg></xml>""",
content_type='text/xml', status=200)
elif return_code == 'SUCCESS':
# 拿到這次支付的訂單號(hào)
out_trade_no = xmlmsg['xml']['out_trade_no']
# 根據(jù)需要處理業(yè)務(wù)邏輯
return HttpResponse("""<xml><return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg></xml>""",
content_type='text/xml', status=200)
當(dāng)然微信回調(diào)的參數(shù)有很多詳細(xì)可以參考https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8
在回調(diào)的時(shí)候可能遇到這樣一個(gè)問題,支付成功以后沒有調(diào)回調(diào)函數(shù),有可能是回調(diào)地址是https然后改為http就行,遇到過這個(gè)坑,具體原因也不知道。服務(wù)器沒有屏蔽https訪問,https證書也沒有問題,把https改為http最后就可以了。
5.安全問題
在使用的過程中商戶系統(tǒng)對(duì)于支付結(jié)果通知的內(nèi)容一定要做簽名驗(yàn)證,并校驗(yàn)返回的訂單金額是否與商戶側(cè)的訂單金額一致,防止數(shù)據(jù)泄漏導(dǎo)致出現(xiàn)“假通知”,造成資金損失。
我在開發(fā)過程中的解決方式是在向微信支付端發(fā)起請(qǐng)求的時(shí)候,把訂單號(hào),金額,簽名等存入數(shù)據(jù)庫(kù),然后在回調(diào)函數(shù)那里進(jìn)行校驗(yàn)判斷。在確認(rèn)跟前面訂單情況一樣的情況下,才進(jìn)行后續(xù)一系列的操作。
最后送給大家一段祝福
# _oo8oo_ # o8888888o # 88" . "88 # (| -_- |) # 0\ = /0 # ___/'==='\___ # .' \\| |# '. # / \\||| : |||# \ # / _||||| -:- |||||_ \ # | | \\\ - #/ | | # | \_| ''\---/'' |_/ | # \ .-\__ '-' __/-. / # ___'. .' /--.--\ '. .'___ # ."" '< '.___\_<|>_/___.' >' "". # | | : `- \`.:`\ _ /`:.`/ -` : | | # \ \ `-. \_ __\ /__ _/ .-` / / # =====`-.____`.___ \_____/ ___.`____.-`===== # `=---=` # # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # #
總結(jié)
以上所述是小編給大家介紹的Python實(shí)現(xiàn)微信小程序支付功能,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
Python編程深度學(xué)習(xí)計(jì)算庫(kù)之numpy
今天小編就為大家分享一篇關(guān)于Python編程深度學(xué)習(xí)計(jì)算庫(kù)之numpy,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
Python使用pandas讀取Excel并選取列轉(zhuǎn)json
這篇文章主要為大家詳細(xì)介紹了通過Python和pyqt5設(shè)計(jì)一個(gè)工具,可以實(shí)現(xiàn)pandas讀取Excel選取列作為鍵或值轉(zhuǎn)json,感興趣的小伙伴可以了解下2025-02-02
使用keras內(nèi)置的模型進(jìn)行圖片預(yù)測(cè)實(shí)例
這篇文章主要介紹了使用keras內(nèi)置的模型進(jìn)行圖片預(yù)測(cè)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06
python實(shí)現(xiàn)的接收郵件功能示例【基于網(wǎng)易POP3服務(wù)器】
這篇文章主要介紹了python實(shí)現(xiàn)的接收郵件功能,結(jié)合實(shí)例形式分析了Python基于網(wǎng)易POP3服務(wù)器接收郵件相關(guān)操作技巧,需要的朋友可以參考下2019-09-09
python采集百度搜索結(jié)果帶有特定URL的鏈接代碼實(shí)例
這篇文章主要介紹了python采集百度搜索結(jié)果帶有特定URL的鏈接代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
opencv+tesseract實(shí)現(xiàn)驗(yàn)證碼識(shí)別的示例
本文主要介紹了opencv+tesseract實(shí)現(xiàn)驗(yàn)證碼識(shí)別的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06

