盘点微信支付里我们踩过的坑

前言

我们现在动辄就要对接微信,但是微信的文档一个是入口隐藏太深,第二错误码也太草率了,最近正好项目不太忙,就把微信相关的东西整理出来,我踩过的坑希望大家就不要去浪费时间了。


一、微信支付流程

微信支付流程
流程图画这么多,简单的概括就是三步:

<1>服务端生成支付参数(服务端)
<2>移动端调起sdk进行支付(移动端)
<3>检查支付结果(服务端)

二、生成支付参数

1.获取code链接

官方文档(统一下单)

1.主方法

# pyton代码

from collections import OrderedDict
import xml.etree.ElementTree as et
import xmltodict


def get_pay_param():
	try:
	    url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
	
	    data = OrderedDict()
	    data['appid'] = 'appid'  # 这里填你的appid
	    data['body'] = 'title'  # 这里是支付时候显示的名字,"增值服务"
	    data['mch_id'] = 'mch_id'  # 商户号
	    data['nonce_str'] = verification_code()  # 随机字符串, 详见verification_code方法
	    data['notify_url'] = notify_url  # 回调地址, 我们这里不用这个, 但是是必传参数, 传空字符串就行
	    data['openid'] = 'open_id'  # openid js支付必传, app支付不传, 后续解释什么openid
	    data['out_trade_no'] = 'order_id'  # 需要支付订单的订单号
	    data['spbill_create_ip'] = 'ip'  # 调用微信支付API的机器IP
	    data['total_fee'] = 'amount'  # 支付金额, 单位是分
	    data['trade_type'] = 'JSAPI'  # openid js支付必传, app支付不传
	    data['sign'] = set_sign(data)  # 签名, 详见set_sign_js方法
	
	    xml_data = xmltodict.unparse({'xml': data}, pretty=True, full_document=False).encode('utf-8')
	    response = requests.post(url, data=xml_data)
	    res_data = response.content.decode()
	
	    data_dict = xmltodict.parse(res_data)
	
	    prepayid = data_dict.get('xml').get('prepay_id')
	    noncestr = data_dict.get('xml').get('nonce_str')
	
	    # 计算app_sign
	    app_data = app_sign(data['appid'], data['mch_id'], prepayid, noncestr)
	exceptException as e:
	   print(e)
	   return dict()
    return app_data

从上往下,这里有几个注意点

<1>这里字典用的是OrderedDict,因为生成签名要求参数按照参数名ASCII字典序排序。

<2>支付金额用分啊!敲黑板,当然这里微信要求的就是分,我们项目里设计最好也要分,千万不要用float,丢精度丢精度!!!

<3>这里是把js支付和app支付混在一起写的,用的时候注意自行去掉。

<4>我这里是只取了必填参数,如果需要扩展还要看微信文档。

# 如果参数正确的话就会收到如下的响应
"app_data": {
        "appId": "wx3c2003853017fb67",
        "nonceStr": "4yuBi0T1FVHuvKlT",
        "package": "prepay_id=None",
        "signType": "MD5",
        "timeStamp": 1606982275,
        "sign": "5C827985D58D8BEC5E0FF893F105578F"
    }

2.工具方法

生成随机码 verification_code()

# 我这里是6位随机码
def verification_code():
    return str("%06d"%random.randint(0, 999999))

生成签名 set_sign()

# key 后面的xxxx是对应商户的secret, 换成你们自己的
# data_dict就是上面的有序字典
def set_sign(data_dict):
    stringA = ''
    for key, value in data_dict.items():
        stringA += key + '=' + str(value) + '&'
    stringSignTemp = stringA + 'key=xxxxxx'
    sign = md5(stringSignTemp).upper()
    return sign

md5 加密 md5()

import hashlib


def md5(str):
    return hashlib.md5(str.encode('utf-8')).hexdigest()

三、app调起sdk进行支付

封装好的代码,直接下载传参数就可以了
这里是app的
这里是js的

四、检查支付结果

如果我们有外网可以访问到的服务器,还是推荐notify_url填我们服务器地址,这样可靠性高一点,如果没有也没关系,我们可以主动查询。

1.理想状态

def check_payment():
	try:
		url = "https://api.mch.weixin.qq.com/pay/orderquery"
        data = OrderedDict()
        data['appid'] = app_id
        data['mch_id'] = mch_id
        data['nonce_str'] = verification_code()
        data['out_trade_no'] = order_id
        data['sign'] = set_sign(data)

        xml_data = trans_dict_to_xml(data)
        response = requests.post(url, data=xml_data)

        res_data = response.content.decode()
        tree = et.fromstring(res_data)
        return_code = tree.find("return_code").text
        if return_code != 'SUCCESS':
            return False

        result_code = tree.find("result_code").text
        if result_code != 'SUCCESS':
            return False

        trade_state = tree.find("trade_state").text
        if trade_state != 'SUCCESS':
            return False
	except Exception as e:
		print(e)
		return False
	return True

参数的话生成支付参数的时候都见过了,就不赘述了

2.异常状态

用户正常流程当然会不异常,我们支付完调用这个接口,确定支付成功,刷新订单状态,但是我们同时也要保证程序的健壮性,对下面的异常进行处理:

1.app支付完不点返回,我们调不到这个接口。
2.app支付完直接上滑杀进程。
3.网络请求时断网或者网络异常。

用户的使用条件我们无法估计,就是有好多我们想得到或者想不到的意外发生,所以订单支付了我们没有及时更新怎么办?

做一个定时任务轮询未支付的订单呀,定时任务的时间根据业务来定,批量处理未支付的订单,确定是真的没有支付还是异常状态!

这也是为什么推荐用微信主动回调的原因了,因为我们能想到的异常在用被动回调的时候就不存在了。


总结

1. 上面的代码全部写在函数里,基本上属于完成度比较高的伪代码,小伙伴们用到的时候可以进一步封装。

2. 是不是又复习到前面的知识点,字典添加值,遍历,字符串拼接等。

3. 因为python中的字典是无序的,这里用到了有序字典,有序字典使用和我们前面说的字典用法是一样的,他只是额外记录了元素的插入顺序,当然也有额外的内存开销。

4. 为什么用python写支付demo,因为文档上有现成的java,php代码,拿来就能用。

5. 支付其实很简单的,主要耗时的可能就是前后端联调,作为一个合格后端开发,我们生成参数后尽量先去自检参数是否正确,这样可以大大节省调试时间。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值