• 后端接口对接注意事项


    后端接口对接的模式范本:

    概念澄清:

    【下单】是个广义上的叫法,并不仅限于支付订单的订单。因为整个过程都围绕一个【seqNo】订单号或流水号这个唯一标识展开,因而统称【下单】。

    【下单】可以是为派发一个优惠券、申请一个支付订单、申请一个发票等等。

    【seqNo】也可以叫orderNo,有唯一性,每次请求都不一样,唯一标识一笔业务。

     

    后端接口需要考虑的点:   

    • 通信层安全验证(可以通过nginx层做https的证书验证工作)
    • 单向https.

    即客户端验证服务端证书。例如:浏览器验证网站证书。

    我们需要做的就是服务端的证书一定是要第三方授信CA签的证书。

    这样浏览器拿到证书可以在本地找到该授信的第三方ca证书来验证网站证书的真伪。

    如果网站的证书自己签名的证书,客户端需要在浏览器中配置该证书自签名使用的的CA证书。

    https单向相比于双向实现方便,也是最基础的保障。不可能http直接在公网上跑,那样业务报文都是明文暴露状态,非常不安全。

    • 双向https

    一般后端交互https双向,基本都是使用自签名的证书。

    客户端需要配置服务端的ca证书,用于解开服务端给我们的其自身的证书。

    服务端同时也需要配置客户端的ca证书,用于解开客户端给服务端的其自身的证书。

    如果是代码实现发送双向https请求,你会发现有两个证书配置,一个是请求方自身的证书,一个是服务端的ca证书。

    https双向优点就是更加安全,通过证书能互相确认彼此身份。在后端交互中常见。单向https在浏览器/服务端中常见。

     

    • 接口层校验:

    接口或者header中有类似于sign的字段,用于验证签名。

    签名的作用就两个:防篡改;防抵赖

    sign = sha256WithRSA(报文,私钥)等方法的模式为【私钥签名、公钥验签】的方式,可以防篡改,防抵赖.但是实现相对较重,需要生成和管理公私钥。

    使用appkey/secretKey模式,使用类似于sign=MD5(报文,secretkey)只能防篡改,因为这个secretKey是双方都知道的.但是实现方式较轻量,也很普遍。

     

    • 数据安全保护

    通信层https只能保证数据在网络或者公网中是密文传输的。

    但是一旦数据过了nginx这关,即解除https证书验证之后,报文数据在内网中就是明文在传输。对应敏感数据不能明文显示。

    复杂安全点的模式可以使用数字信封模式:

    即提供两个字段:

    partnerData:敏感数据的加密值,使用对称加密的,例如:AES算法。

    dekey:随机对称密钥的加密值,使用非对称加密的,例如:RSA算法

    partnerData=AES(敏感数据,随机对称密钥)  

    dekey=RSA(随机对称密钥,接收方的公钥)

    解密的过程就是加密的逆过程,先用自己的私钥解出对称密钥,再使用对称密钥解开敏感数据。

    因为基于公私钥,所以只有私钥持有者才能解开这个数字信封。安全性非常好。

     

    • 业务授权校验:

    通信层可以进来,验签能通过。但是业务授权也要鉴别,例如:同样可以调用派发优惠券接口,但是商户A只能发商户A商品的优惠券。

    接口或者header中有类似于appkey/appCode/authCode等类似功能字段,该字段和验签绑定。通过该字段查询配置,确认该请求是否有该业务的权限。

     

    • 防重发攻击:

    https单向中多见,https双向中少见。主要预防攻击不要流到业务层。

    1.防止错误的报文重复攻击,一般错误报文验签直接可以过滤。

    2.防止正确的报文重复攻击

    一般在接口或者header中有timestamp/nonce/messageId等字段,这些字段每次请求都会不一致。

    如果报文被截获,重放攻击,可能由于timestamp时间和服务器时间相差很远,或者相关nonce字段已经被缓存过,无法通过。

    同时可以结合幂等措施,即被处理过的业务不会重复执行。

     

    • 实现幂等:

    接口中有seqNo字段,可以叫订单号/流水号。

    一个seqNo就对应了一次业务下单,同样的流水号无论请求多少次,结果都是一样的,不会重复做。

    防止请求在通信中丢失,请求方无法判断该业务的实际状态,是【还未送达】或【处理完了,回程时丢失】

    实现幂等后,请求方可以使用相同seqNo进行下单,服务端如果处理过该seqNo订单,就将之前的处理结果返回,如果没处理就收单继续处理。

     

    • 提供查询

    为什么提供了幂等还要提供查询?

    查询和幂等的作用区别就在于,很多时候请求方请求出现异常,没有明确的答案,如果希望业务继续,则可以幂等请求。

    例如该用户派发优惠券,如果发生异常则继续幂等派发即可。

    如果需要根据实际业务状态决定如何操作,则需要先查询。

    例如:很多有时效的业务,抢购业务,用户下单异常,最终没抢到货。

    肯定是先查询,如果刚才订单实际成功,则给用户退款。如果刚才订单未成功,则直接关闭业务,这单子不用继续做下去了。

     

    • 异步通知:

    下单接口如果是同步接口,肯定没有实现异步通知的必要。

    很多下单接口是异步接口,真正的业务状态在同步中无法返回,同步仅仅返回已收单。

    异步通知的作用:能增强业务的时效性,同时也能减少请求方轮询导致的压力。

    如果收到明确通知,请求方当即可以触发下一步操作,如果没有通知或通知丢失,请求方只能挂单等待异常处理时主动查询确认状态。

     

    • 是否需要对账

    一般后端对接的业务接口,基本都需要对账。

    对账最大的问题是【跨天】,例如:请求方请求时间为凌晨:23:59:59.但是接收方收到的时间为次日:00:00:04

    假如按照T+1对账,那在T日临界点,总可能出现对不平的情况。请求方有该笔账,但是接收方没有。

    我们不讨论【勾对】等其他实现方式。

    如果可能,在定义接口的时候,可以讨论清楚对账方式及以哪方时间为准。避免后续对账开发困难。

    例如:在下单接口中添加objectData字段,以请求方的该字段作为对账时间依据。

     

    • 考虑升级

    对接的任何一方都有在业务进行中要升级接口的可能。但是要避免需要停服、及互相依赖的局面,例如:大家约定一个时间,半夜你先升级,我在升级。

    场景1:公私钥泄露需要更换。

    可以在接口中添加keyIndex来标识密钥的版本或者signType字段来标识签名的算法。

    这样请求方报文中使用什么版本的密钥,接收方就使用什么版本的密钥解密。互相不依赖。提前配置好即可。

    场景2:接口字段升级

    下单接口有新增字段,选择升级接口版本号,形成一个新接口。老接口仍保留。接收方先升级,请求方择机升级,互不影响。

    查询同理。

     

    • 考虑异常

    网络异常、网络波动、今天我灾备、明天他机房维护等。这些单个事件都是小概率,但是这样的事件非常多。

    网络异常也导致很多业务异常,我们要充分考虑的异常导致的挂单和中断的情况,做好异常处理和自愈功能。

    例如:对账往ftp上投送对账文件。可能网络异常,今天的文件没放上去;或者今天的放上去了,但是出问题需要重新放;可能灾备停了两天,在进行对账等等

    ps:不要忽略这些小概率事件,没有预案,只要发生一次,造成的异常业务笔数可能手动处理很久。

     

    • 接口效率

    考虑这个接口的负载是很关键的步骤。同步接口压力大点,异步接口可以使用MQ进行削峰填谷相对压力小点。

    提升效率,控制并发是一个非常庞大的体系。常见的方式:
    1.共享数值字段,我们只做累加

    2.每个用户独立有一条记录,将并发化解。

    4.用插入代替更新,分段锁库存等,使用<=0代替=0,防止极限情况击穿等。

    5.分库分表,避免热点表和数据的阻塞。

    6.注意风控,报警等情况。

    ...............

     

    • 示例:

    {
    "authCode": "123", 业务认证码
    "appCode": "123", 请求方
    "deKey":"frfferdfa" 对称密钥加密值
    "partnerData": "22", 敏感数据加密值
    "seqNo": "123",请求流水
    "timestamp": "202107201653123", 时戳
    "keyIndex": "1", 加密密钥版本
    "sign": "123" 签名
    }

     

    后端一般都是业务接口,相对来说更加复杂,且参数组成和路径命名没有一个统一的模式,每家都不一样,尤其很多传统厂商。 

    前端接口相对规范的多,基本都是RESTFUL风格。

     

    前端接口定义示例:

    1       获取用户订单详情

    接口路径:http://ip:port/sapo/biz/1/0/users/{user-uuid}/orders

    请求方法:GET

     

    l  说明:查询用户订单详情

    l  请求方:小程序

    l  接收方:服务端

     

    请求头:

    Location

    Name

    Type

    Description

    Required

    Example

    Header

    authorization

    str

    用户token

    1

     

    Header

    Content-Type

    str

    application/json

    1

    application/json

     

    请求路径参数:

    Location

    Name

    Type

    Description

    Required

    Example

    Path

    user-uuid

    str

    用户uuid

    1

     

     

    请求参数:

    Name

    Type

    Description

    Required

    Example

    createTime

    str

    创建时间 [格式:yyyyMMddHHmmss]

    1

     

    lastUpdateTime

    str

    最后更新时间 [格式:yyyyMMddHHmmss]

    1/0

     

    status

    num

    状态:0-无效,1-有效

    1

    1

     

    返回参数:

    Name

    Type

    Description

    Required

    Example

    resCode

    str

    应答码

    1

    0000

    resDesc

    str

    应答信息

    1/0

    success

    resData

    obj

    应答数据

    1/0

     

     

    resData结构:

    Name

    Type

    Description

    Required

    Example

    total

    num

    总个数

    1

     

    orderInfoList

    list

    订单对象实体集合

    1

     

     

    orderInfo结构:

    Name

    Type

    Description

    Required

    Example

    createTime

    str

    创建时间 [格式:yyyyMMddHHmmss]

    1

     

    orderNo

    str

    订单号

    1

     

    serviceSpecInfo

    obj

    [服务规格]对象实体

    1

     

    status

    num

    状态:1-待支付,2-已支付,3-待执行,4-执行中,5-已完成,6-已取消,7-已下单

    1

    7

    expireTime

    str

    失效时间,格式:yyyyMMddHHmmss

    1/0

     

    invoiceFlag

    num

    是否开过发票标识,0-未开发票,1-已开发票

    1

    0

    totalFee

    num

    订单总价,单位:

    1

     

    payFee

    num

    最终支付金额(单位:)

    1/0

     

     

    serviceSpecInfo结构:

    Name

    Type

    Description

    Required

    Example

    code

    str

    规格类型代码

    1

     

    name

    str

    规格名(30分钟速洗\20分钟烘干)

    1

     

    detail

    str

    规格描述(30分钟速洗\20分钟烘干)

    1/0

     

     

    请求示例:

    GET   192.168.1.11:9032/sapo/biz/1/0/users/123/orders

    返回示例:

    {

        "resCode""0000",

        "resDesc""success",

        "resData": {

            "total"2,

            "orderInfoList": [

                {

                    "createTime""20220517194521",

                    "deviceExeRemainTime"23,

                    "expireTime"null,

                    "orderNo""456",

                    "payFee"0,

                    "serviceSpecInfo": {

                        "code""washSpec1",

                        "detail"null,

                        "name""washSpec1"

                    },

                    "status"1,

                    "totalFee"0

                }

            ]

        }

    }

     

     

    本文来自博客园,作者:wanglifeng,转载请注明原文链接:https://www.cnblogs.com/wanglifeng717/p/16213202.html

     

     

  • 相关阅读:
    esdump离线安装
    用Python获取网络数据
    java计算机毕业设计石家庄市居家养老服务平台源程序+mysql+系统+lw文档+远程调试
    Activiti可视化流程管理器
    第四章 文件管理 四、文件的物理结构(文件分配方式)
    【SQL刷题】Day10----SQL高级过滤函数专项练习
    在大数据相关技术中,HBase是个分布的、面向列的开源数据库,是一个适合于非结构化数据存储的数据库。
    SpringBoot实现定时任务的三种方式
    centos7安装mysql5.7步骤(图解版)
    小程序之后台数据动态交互及WXS的使用 (5)
  • 原文地址:https://www.cnblogs.com/wanglifeng717/p/16213202.html