Python實現微信小程序支付功能

因爲最近本身在作小程序的支付,就在這裏簡單介紹一下講一下用python作小程序支付這個流程。固然在進行開發以前仍是建議讀一下具體的流程,清楚支付的過程。
php

1.支付交互流程

固然具體的參數配置能夠參考官方文檔https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1html

 2.獲取openid(微信用戶標識)

 1 import requests  2  
 3 from config import APPID, SECRET  4  
 5  
 6 class OpenidUtils(object):  7  
 8     def __init__(self, jscode):  9         self.url = "https://api.weixin.qq.com/sns/jscode2session"
10         self.appid = APPID  # 小程序id
11         self.secret = SECRET  # 不要跟後面支付的key搞混
12         self.jscode = jscode    # 前端傳回的動態jscode
13  
14     def get_openid(self): 15         # url必定要拼接,不可用傳參方式
16         url = self.url + "?appid=" + self.appid + "&secret=" + self.secret + "&js_code=" + self.jscode + "&grant_type=authorization_code"
17         r = requests.get(url) 18         print(r.json()) 19         openid = r.json()['openid'] 20  
21         return openid

3.支付請求

 1 # -*- coding:utf-8 -*-
 2 import requests  3 import hashlib  4 import xmltodict  5 import time  6 import random  7 import string  8 import urllib2  9 import sys  10 
 11 
 12 class WX_PayToolUtil():  13     """ 微信支付工具 """
 14 
 15     def __init__(self, APP_ID, MCH_ID, API_KEY, NOTIFY_URL):  16         self._APP_ID = APP_ID  # 小程序ID
 17         self._MCH_ID = MCH_ID  # # 商戶號
 18         self._API_KEY = API_KEY  19         self._UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder"  # 接口連接
 20         self._NOTIFY_URL = NOTIFY_URL  # 異步通知
 21 
 22     def generate_sign(self, param):  23             '''生成簽名'''
 24             stringA = ''
 25             ks = sorted(param.keys())  26             # 參數排序
 27             for k in ks:  28                 stringA += (k + '=' + param[k] + '&')  29             # 拼接商戶KEY
 30             stringSignTemp = stringA + "key=" + self._API_KEY  31             # md5加密,也能夠用其餘方式
 32             hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))  33             sign = hash_md5.hexdigest().upper()  34             return sign  35 
 36     '''
 37  # python2另一種實現方法  38  def generate_sign(self, params):  39  ret = []  40  for k in sorted(params.keys()):  41  if (k != 'sign') and (k != '') and (params[k] is not None):  42  ret.append('%s=%s' % (k, params[k]))  43  params_str = '&'.join(ret)  44  params_str = '%(params_str)s&key=%(partner_key)s' % {'params_str': params_str, 'partner_key': key}  45 
 46  reload(sys)  47  sys.setdefaultencoding('utf8')  48 
 49  params_str = hashlib.md5(params_str.encode('utf-8')).hexdigest()  50  sign = params_str.upper()  51  return sign  52     '''
 53 
 54     def getPayUrl(self, orderid, openid, goodsPrice, **kwargs):  55         """向微信支付端發出請求,獲取url"""
 56         key = self._API_KEY  57         nonce_str = ''.join(random.sample(string.letters + string.digits, 30))  # 生成隨機字符串,小於32位
 58         params = {  59             'appid': self._APP_ID,  # 小程序ID
 60             'mch_id': self._MCH_ID,  # 商戶號
 61             'nonce_str': nonce_str,  # 隨機字符串
 62             "body": '測試訂單',  # 支付說明
 63             'out_trade_no': orderid,  # 生成的訂單號
 64             'total_fee': str(goodsPrice),  # 標價金額
 65             'spbill_create_ip': "127.0.0.1",  # 小程序不能獲取客戶ip,web用socekt實現
 66             'notify_url': self._NOTIFY_URL,  67             'trade_type': "JSAPI",  # 支付類型
 68             "openid": openid,  # 用戶id
 69  }  70         # 生成簽名
 71         params['sign'] = self.generate_sign(params)  72 
 73         # python3一種寫法
 74         param = {'root': params}  75         xml = xmltodict.unparse(param)  76         response = requests.post(self._UFDODER_URL, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})  77         # xml 2 dict
 78         msg = response.text  79         xmlmsg = xmltodict.parse(msg)  80         # 4. 獲取prepay_id
 81         if xmlmsg['xml']['return_code'] == 'SUCCESS':  82             if xmlmsg['xml']['result_code'] == 'SUCCESS':  83                 prepay_id = xmlmsg['xml']['prepay_id']  84                 # 時間戳
 85                 timeStamp = str(int(time.time()))  86                 # 5. 五個參數
 87                 data = {  88                     "appId": self._APP_ID,  89                     "nonceStr": nonce_str,  90                     "package": "prepay_id=" + prepay_id,  91                     "signType": 'MD5',  92                     "timeStamp": timeStamp,  93  }  94                 # 6. paySign簽名
 95                 paySign = self.generate_sign(data)  96                 data["paySign"] = paySign  # 加入簽名
 97                 # 7. 傳給前端的簽名後的參數
 98                 return data  99 
100         # python2一種寫法
101         '''
102  request_xml_str = '<xml>' 103  for key, value in params.items(): 104  if isinstance(value, str): 105  request_xml_str = '%s<%s><![CDATA[%s]]></%s>' % (request_xml_str, key, value, key,) 106  else: 107  request_xml_str = '%s<%s>%s</%s>' % (request_xml_str, key, value, key,) 108  request_xml_str = '%s</xml>' % request_xml_str 109 
110  # 向微信支付發出請求,並提取回傳數據 111  res = urllib2.Request(self._UFDODER_URL, data=request_xml_str.encode("utf-8")) 112  res_data = urllib2.urlopen(res) 113  res_read = res_data.read() 114  doc = xmltodict.parse(res_read) 115  return_code = doc['xml']['return_code'] 116  if return_code == "SUCCESS": 117  result_code = doc['xml']['result_code'] 118  if result_code == "SUCCESS": 119  doc = doc['xml'] 120  data = { 121  "appId": self._APP_ID, 122  "nonceStr": nonce_str, 123  "package": "prepay_id=" + doc["prepay_id"], 124  "signType": 'MD5', 125  "timeStamp": str(int(time.time())), 126  } 127  # paySign簽名 128  paySign = self.generate_sign(data) 129  data["paySign"] = paySign # 加入簽名 130  return data 131  else: 132  err_des = doc['xml']['err_code_des'] 133  return err_des 134  else: 135  fail_des = doc['xml']['return_msg'] 136  return fail_des 137         '''

固然你可能會遇到的錯誤有簽名錯誤,通常的狀況是你的appSecret和商戶號的API密鑰兩個弄錯了,固然若是不是還有多是其餘問題,解決方案連接https://www.cnblogs.com/wanghuijie/p/wxpay_sign_error.html前端

其餘的支付方式獲取用戶的ip地址能夠經過socket.gethostbyname(socket.gethostname())方法來獲取。python

4.支付回調

 1 # 統一下單回調處理
 2  
 3 import xmltodict  4  
 5 from django.http import HttpResponse  6  
 7 def payback(request):  8     msg = request.body.decode('utf-8')  9     xmlmsg = xmltodict.parse(msg) 10  
11     return_code = xmlmsg['xml']['return_code'] 12  
13     if return_code == 'FAIL': 14         # 官方發出錯誤
15         return HttpResponse("""<xml><return_code><![CDATA[FAIL]]></return_code> 16  <return_msg><![CDATA[Signature_Error]]></return_msg></xml>""", 17                             content_type='text/xml', status=200) 18     elif return_code == 'SUCCESS': 19         # 拿到此次支付的訂單號
20         out_trade_no = xmlmsg['xml']['out_trade_no'] 21  
22         # 根據須要處理業務邏輯
23  
24         return HttpResponse("""<xml><return_code><![CDATA[SUCCESS]]></return_code> 25  <return_msg><![CDATA[OK]]></return_msg></xml>""", 26                             content_type='text/xml', status=200)

固然微信回調的參數有不少詳細能夠參考https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8git

在回調的時候可能遇到這樣一個問題,支付成功之後沒有調回調函數,有多是回調地址是https而後改成http就行,遇到過這個坑,具體緣由也不知道。服務器沒有屏蔽https訪問,https證書也沒有問題,把https改成http最後就能夠了。web

5.安全問題

在使用的過程當中商戶系統對於支付結果通知的內容必定要作簽名驗證,並校驗返回的訂單金額是否與商戶側的訂單金額一致,防止數據泄漏致使出現「假通知」,形成資金損失。數據庫

我在開發過程當中的解決方式是在向微信支付端發起請求的時候,把訂單號,金額,簽名等存入數據庫,而後在回調函數那裏進行校驗判斷。在確認跟前面訂單狀況同樣的狀況下,才進行後續一系列的操做。django

最後送給你們一段祝福json

#                                  _oo8oo_
#                                 o8888888o
#                                 88" . "88
#                                 (| -_- |)
#                                 0\  =  /0
#                               ___/'==='\___
#                             .' \\|     |# '.
#                            / \\|||  :  |||# \
#                           / _||||| -:- |||||_ \
#                          |   | \\\  -  #/ |   |
#                          | \_|  ''\---/''  |_/ |
#                          \  .-\__  '-'  __/-.  /
#                        ___'. .'  /--.--\  '. .'___
#                     ."" '<  '.___\_<|>_/___.'  >' "".
#                    | | :  `- \`.:`\ _ /`:.`/ -`  : | |
#                    \  \ `-.   \_ __\ /__ _/   .-` /  /
#                =====`-.____`.___ \_____/ ___.`____.-`=====
#                                  `=---=`
#
#
#               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#                          強大爺保佑         永不宕機/永無bug
啦啦啦
相關文章
相關標籤/搜索