• 支付平台架构


    支持多种支付方式的支付平台架构,示例使用 Python Tornado 框架。

    用到了工厂模式和模板方法模式。

    工厂模式:子类的某个方法要根据情况来决定用什么类去实例化对象。

    模板方法模式:用来定义算法的各个步骤,并将某些步骤交由子类实现。

    流程

    流程为:下单、用户付款、确认用户付款、发货。

    • 下单:客户端调用该接口,上传必要信息,如商品 ID、收货人,服务器创建订单,返回一个唯一的订单号。
    • 用户付款:付款方式由支付渠道提供。
    • 确认用户付款:一般有两种方式:回调与主动验单。
      • 回调:用户支付成功后,充值渠道发起请求到我方服务器。比如支付宝。
      • 主动验单:充值渠道将充值数据返回给客户端,客户端将其提交到服务器,服务器拿着数据去充值渠道验单。比如苹果支付、谷歌支付。
    • 通知发货。

    设计

    • 充值渠道可以共用创建订单、发货的方法
    • 由于回调一般为 POST 请求,所以只能通过 URL 来区分不同的充值渠道,而不能使用相同的 URL 然后再通过参数来区分。
    • 在基类中定义需要实现的模板方法,由子类(具体的支付渠道)去具体实现。

    所以整个基类的结构如下:

    class AbstractPay(tornado.web.RequestHandler):
    
        def create_order(self):
            """创建订单"""
            pass
    
        def respond_callback(self):
            """响应支付方回调"""
            raise NotImplementedError()
    
        def verify_order(self):
            """向支付方验证订单"""
            raise NotImplementedError()
    
        def notify_delivery(self):
            """通知发货"""
            pass
    

    raise NotImplementedError() 是需要子类去实现的方法,pass 的表示由基类实现,子类共用的的方法。

    URL 如下

    handlers = [
        ('/' + API_VERSION + 'create_order/', CreateOrderHandler),
        ('/' + API_VERSION + 'callback/' + '(?P<channel>[^/]+)', RespondCallbackHandler),
        ('/' + API_VERSION + 'verify/' + '(?P<channel>[^/]+)', VerifyHandler),
    ]
    

    根据 channel 实例化对应的类,然后调用 respond_callbackverify_order 方法,验证成功后再通知发货。

    响应回调的代码如下:

    def post(self, channel):
        pay_channel = globals()[channel.title()]()
        pay_channel.respond_callback()
    

    确保成功

    需要确保我们的主动请求 —— 验证订单和通知发货一定成功。

    1. 在第一次请求失败后,隔一定时间再次发起请求,如果还是失败,增大等待间隔,再次发起请求,以此类推,直到一定次数之后,抛出异常。
    2. 增加定时任务,定期去验证订单和通知发货。

    异常处理

    所有支付渠道可以共用一个异常处理函数。异常处理顺序由具体到抽象,由自定义到内置。

    这里以 Tornado 为例,在 AbstractPay 中重写 write_error() 即可。

    使用时只需要在子类中抛出对应异常。

    安全

    流程如下:

    • 回调订单号应该存在并且为 等待支付 状态
    • 支付金额和创建订单时的金额一致
    • 商品 ID 一致
    • 验证签名

    以上任何一个验证失败,则忽略该回调/验证数据。

    • 第一步为了防止多次发货
    • 第二三步确保购买的商品、付款的金额一致
    • 验证签名确保信息来源正确

    由于各种渠道回传的数据不一致,所以这个由子类自己实现。

  • 相关阅读:
    cxgrid显示行号
    编写服务端程序的要点
    创建自己的数据库
    cxgrid动态创建footer
    build with runtime package
    TQueue,TStack
    能用图形分析
    Laravel任务调度
    PHP 判断点是否在多边形内
    判断一个点是否在某个区域内。百度,高德,腾讯都能用。(php版)
  • 原文地址:https://www.cnblogs.com/jay54520/p/8652582.html
Copyright © 2020-2023  润新知