1.前言
2010年前,大型社交网站如腾讯QQ、新浪微博都搭建了开放平台。中小型互联网公司接入开放平台,能够获取社交平台的海量用户,有效的降低获客成本,获得社交平台的其他能力。对于用户而言,用一个社交帐号登录各种网站或APP,体验也会更好。后来,许多行业如电商、金融等都开放了业务核心API。这些行业的竞争非常激烈,公司希望通过开放平台与合作伙伴保持更高效的协作,实现资源交换或者流量变现。
广义的开放平台是个庞大的结构,它站在核心业务系统的前面,承接着所有的流量。公司所有的客户端比如Web站点、手机APP、智能硬件都对接开放平台API,只是各自的权限不同,可以访问的资源不同。狭义的开放平台只是打开了一扇门,让合作伙伴进来参与业务互动。从业务层面上看,开放平台仅仅是流量渠道之一。
本文重点讨论的是狭义的开放平台。
2.需求分析
2.1 总体需求
业务系统相当于酒店,开放平台是专门招待外宾的特殊客房,合作伙伴(以下统称商户)就是外宾。外宾进入酒店有专门的通道,不和其他客户的共用。外宾可以在房间睡觉、点餐,但是不能去其他房间串门。主观上,酒店希望接纳更多的外宾,但是招待能力始终有上限,因此一定要限制外宾活动的频率,否则没有足够的人力招待其他的住客。在系统设计上,开放平台有四个重要的要求:
- 1)接口访问授权:商户帐号仅能访问被授权的接口,也不允许访问到其他商户的资源。
- 2)接口访问限流:商户访问接口必须限流,不能对公司的核心系统造成冲击。
- 3)内部业务隔离:商户最忌讳接口出入参数频繁变化,内部系统要做好业务规划和多版本设计,尽可能保证接口出入参数不变动。
- 4)数据安全:加密敏感数据,比如用户手机号、银行卡号。
2.2 平台角色
开放平台的使用者只有两个:商户和平台管理员,平台管理员可以划分为超级管理员、商务经理、产品经理。
- 1)超级管理员:拥有最高系统管理权限。
- 2)商务经理:商务经理负责与商户洽谈合作事宜,审核商户资料的真实性,推动合作的进度。
- 3)产品经理:产品经理根据商务经理与商户签订的合同,确定产品流程的细节,解答商户的业务疑问,联合开发人员协助商户对接API。如果有需要,甚至要为商户设计新的API。
2.3 项目构成
- 1)开放API
商户的开发水平和意愿不一样,接入方式可以分为三种:
- 全API:商户端技术人员开发前端页面,后端调用开放平台API,包装为自己的前端接口,串联这些前端接口完成产品流程。
- 内嵌H5:商户端技术人员在产品的合适位置嵌入开放平台提供的H5地址,用户可以打开这个地址,完成产品流程。
- 内嵌SDK:开放平台提供Android或IOS平台的SDK,商户端技术人员自行集成在产品中,完成产品流程。
- 2)商户服务系统
商户服务系统至少包含商户入驻、参数配置功能,部分业务还需要佣金结算、订单统计等功能。
- 商户入驻:商户先提交企业资料,商务经理审核通过之后,商户才能正常访问开放API。
- 参数配置: 配置对接开放API的一些参数,比如接入方式。
- 3)商户管理系统
商户管理系统主要用于查询、修改、编辑商户信息、审批商户的配置信息以及其他辅助功能。
3.系统架构
3.1 系统架构
采用成熟的分布式组件实现架构,如下图所示:
3.2 业务边界
为了业务的整体可控,核心业务系统不应该迎合开放平台的变化,而是开放平台适配核心系统。开放平台的业务边界是只做渠道功能,不做核心业务,通过调用核心系统的接口完成业务操作。
3.3 数据闭环
核心系统没有意愿保存商户ID或者其他与渠道有关的数据,数据闭环是指商户发起的请求(比如创建订单),先保存在开放平台的数据库,开放平台再向核心系统发起请求。这份数据并不需要特别完整,但是至少包含业务主键。当有需要的时候,通过查询核心系统接口来弥补缺失的数据。自主冗余数据的好处有两点:1.减少了调用链,加快接口查询速度;2.更容易实现根据商户ID分页查询数据、订单统计、佣金结算等功能。
4 API设计
4.1 RESTful风格
接口设计遵循 RESTful 协议,它有下面的特性:
- 资源是由 URI 来指定,URI 中可以包含请求参数。
- 对资源的操作如获取、创建、修改和删除,要采用 HTTP 协议提供的动作标识 如GET、POST、PUT 和 DELETE 等。
- 资源的表现形式可以是XML、HTML、JSON,多数采用JSON。
采用RESTful API的好处有三点:
- 基于HTTP协议,轻量级,使用广泛
- 接口设计面向资源,具有自解释性。
- 以 XML,JSON 做数据交换,格式简单。
在实际的运用中,严格遵循 RESTful 协议有下面三点缺陷:
- 1)HTTP动词过多
开发人员使用过多的HTTP动词,心智负担较大;用动词标记操作资源满足不了复杂的业务需求,最后还得通过接口名称来区分;某些请求如 PUT、DELETE 可能被中间层设备过滤掉。
- 2)URL支持参数
URL里面包含参数占位符比如GET /Api/Orders/{id}/OrderItems/{id}
,阅读性不佳。如果根据 URL 来统计接口调用次数,分析系统需要额外处理相同地址不同参数的情况。
- 3)HTTP状态码表现力不足
通过20X、30X、4XX、5XX等有限的响应码无法表达复杂的业务状态。
为了解决以上三点缺陷,建议接口遵循如下规范:
- HTTP 动词仅采用 GET、POST。
- URL里面不允许使用参数占位符。
- 返回结果采用自定义的业务状态码。
通常每个接口都有一个资源地址,为了更灵活些,可以设计为仅有一个入口地址,在参数里面增加接口名称,来区分不同的业务操作。参考淘宝API文档,如下所示:
请求地址:http://gw.api.taobao.com/router/rest
请求参数:
名称 | 类型 | 必须 | 描述 |
---|---|---|---|
method | String | 是 | API接口名称,例如:taobao.user.buyer.get |
timestamp | String | 是 | 时间戳,格式为yyyy-MM-dd HH:mm:ss,时区为GMT+8,例如:2015-01-01 12:00:00 |
4.2 分类原则
遵循MECE原则,根据业务领域进行接口分类。
MECE(发音me see)是Mutually Exclusive Collectively Exhaustive的缩写,意思是“相互独立,完全穷尽”,也就是对问题的分析,能够做到不重复、不遗漏,从而直达问题的核心,并找到问题的解决方法。由《金字塔原理》作者巴巴拉·明托1973年发明,也是麦肯锡思维过程的一条基本准则。
4.3 版本管理
不同版本的相同接口,将版本号标识统一后置,如下所示:
# 老版本
http://openapi.test.com/order/create_order
# 新版本
http://openapi.test.com/order/create_order/v2
4.4 返回数据
所有接口的返回数据都采用固定的JSON格式,如下所示:
{
"code":200,
"msg":"OK",
"data":{
"order_id":"2012120112304512",
"product_name":"男士卫衣"
}
}
- code:父编号,一般是请求成功、异常等标识。
- msg:父编号信息,一般是请求结果的信息提示。
- data:具体的业务数据。
4.5 安全措施
- 1)接口MD5签名
-
对所有API请求参数(包括公共参数和业务参数,但除去sign参数、值为空和值为数组类型的参数),根据参数名称的ASCII码表顺序升序排列,比如:foo=1, bar=2, foo_bar=3, foobar=4排序后的顺序是bar=2, foo=1, foo_bar=3, foobar=4。
-
将排好序的参数名、参数值用&拼装在一起,采用utf-8编码,比如:bar=2&foo=1&foo_bar=3&foobar=4。
-
在拼装的字符串尾部加上预先分配的密钥值 secret_value 后,再进行MD5算法摘要,如:md5(bar=2&foo=1&foo_bar=3&foobar=4&secret=secret_value)。
- 2)数据加密
加密敏感数据比如用户信息,常见加密算法可以是RSA或者AES。
- 3)IP白名单
在接口访问的前置层,只允许在白名单里的IP的请求。商户通过商户服务系统自行管理IP白名单。
4.6 数据推送
数据推送是指系统主动通知商户数据的变化,满足部分商户对数据的实时性要求。举个例子,商户创建订单成功,通过订单查询接口GET http://openapi.domain.com/query_order
获得订单状态。如果商户希望尽快知道订单状态,可以定时轮询订单查询接口,但是效率低且浪费资源。系统主动通知商户订单的状态,能有效解决这个问题。商户需要按规范开发接口,接受指定格式的数据。数据推送增加系统了的复杂性,又会造成两个问题:
- 业务状态的顺序性
订单有多个状态而且有业务顺序性,由于网络延迟的未知性,订单状态数据可能无序的推送给商户,这时商户可以通过业务逻辑去保证订单状态的正确性。
- 推送数据可能遗漏
系统推送数据一般采用MQ异步发送,即便有手段保证消息不丢失,但是商户的网络故障依然会造成推送失败。这种故障有两个方式解决:1.系统在T+1时段提供T日的对账文件,里面包含订单号和订单状态,商户根据对账文件批量更新遗失的订单号状态;2.商户定时轮询订单状态。
4.7 API文档
为了便于商户查阅和测试API,采用 https://www.apifox.cn/ 管理API文档。