微信支付最核心的两个功能就是
微信支付
和支付回调通知
1.准备
-
配置信息
-
appid
进入微信公众号里面的开发>基本配置
就有
appid.jpg
-
mch_id
商户的id -
mch_key
商户的密钥 -
notify_url
这个支付结束后的回调 URL。 -
openid
这个是用户的openid,获取这个方式根据不同的业务获取。公众号业务的可以参考 微信公众号网页授权
-
-
添加支付配置目录
添加服务器的域名

2.业务流程
请求统一支付接口,封装数据,返回给客户端进行调用支付功能,然后等待支付结果回调。
2.1.H5 微信支付
2.1.1.辅助工具
辅助工具主要是为了方便一些复杂流程
- 32位的随机字符串
def nonce_str():
# 生成字符串
return random_number(32)
def random_number(iterate, value=""):
# 构建一个字符集
strs = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z"
]
if iterate == 0:
return value
# 递归方式生成字符串
return value + random_number(iterate - 1, random.choice(strs))
- 签名
"""
签名验证地址: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
"""
def sign(sign_key_value, key):
# key = mch_key
# 拼接参数
string_sign_temp = ""
for k, v in [(k, sign_key_value[k]) for k in sorted(sign_key_value.keys())]:
if v is not None or v != "":
string_sign_temp += "{}={}&".format(k, v if v else str(v))
# MD5加密
import hashlib
_md5_obj = hashlib.md5()
_pre_sign = string_sign_temp + "key={}".format(key)
_md5_obj.update(_pre_sign.encode(encoding='utf-8'))
_sign = _md5_obj.hexdigest().upper()
return _sign
辅助工具实现参考来源:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
2.1.2.统一下单必须参数
# 封装必要的数据
{
'appid': appid,
'mch_id': mch_id,
'device_info': "WEB",
'nonce_str': nonce_str,
'body': body,
'out_trade_no': out_trade_no,
'total_fee': total_fee,
'spbill_create_ip': spbill_create_ip,
'notify_url': notify_url,
'trade_type': trade_type,
'openid': openid,
# 其他需要的字段
}
这个数据作为一下的 params
2.1.3.构建请求的xml
def json2xml(params):
# params 是 `2.1.2` 所需要的数据
# params 是需要进行转换的 dict
import xmltojson # pip install xmltojson
return xmltodict.unparse(str, pretty=True)
def params_exchanging(params):
# 生成签名之后,拼接并转换成 xml
_sign = sign(params)
params['sign'] = _sign
return json2xml(params)
这个返回的数据用于下面统一下单的 data_xml
2.1.4.统一下单
参考文档:统一下单
def unified_ordering(data_xml):
import requests # pip install requests
import xmltojson
import json
_unified_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
_res = requests.post(_unified_url, data=data_xml)
# 返回一个 dict 对象,讲 返回的 xml 转换成方便操作的 json
return json.loads(json.dumps(xmltodict.parse(wx_msg), indent=1))
返回的数据可以直接使用,但是为了进一步方便前端的工作,我们需要封装成直接让前端调起H5支付的功能。
2.1.4.处理统一下单数据
参考文档: 微信内H5调起支付
# 处理数据之前需要判断数据的可用性哦,看统一下单的文档有解释
#
# unified_order_result 格式如下:
# {
# "xml": {
# "appid": "dasdasdsad",
# ...
# }
# }
#
def jsapi_resolve(unified_order_result, mch_key):
import datetime
_dict = {
"appId": unified_order_result['xml']['appid'],
"timeStamp": str(datetime.datetime.now().timestamp())[0:10],
"nonceStr": unified_order_result['xml']['nonce_str'],
"package": "prepay_id={}".format(unified_order_result['xml']['prepay_id']),
"signType": "MD5"
}
_sign = sign(_dict, mch_key)
_dict['paySign'] = _sign
return _dict
到这里,返回的数据就可以提供微信支付了。
2.2.支付回调通知处理
文档参考:支付结果通知
支付回调通知需要是 Post 的请求API,并且不能有任何参数要求。
2.2.1.解析数据
使用 Flask 作为后台
from flask import request, Flask, jsonify # pip install flask
from flask_core import CORS # pip install flask_core
app = Flask(__name__)
@app.route("/api/wx/payment/callback")
def payment_callback():
# 微信传过来的数据
_data_recv = request.data
import xmltojson
import logging
# 微信需要返回一个固定的数据,在没有问题下,一般都写死了。
try:
_json_data = json.loads(json.dumps(xmltodict.parse(_data_recv), indent=1))
logging.warning("{}".format(_json_data))
# TODO 业务逻辑处理...
except Exception as err:
logging.exception(err)
finaly:
return """
<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>
"""
3.总结
- 微信的文档确实很难过;
- 微信支付的错误返回确实很难过,很多问题返回同一个错误信息;
- 很多时候,需要做一个笔记,毕竟微信支付的功能被用好多次,但是每次都得重新再来,不想了;
- 微信的文档挺多的,但是感觉没有一个统一的感觉;
5.微信公众号支付文档
网友评论