整体思路沿用企业邮的接口URL规则定义,将action放到URL中,避免被HTTP Method数量以及规范约束; 满足当前json的数据请求的同时,需要考虑后续的流式请求处理; 部分参考Restful API(以资源为中心)的设计思路及优秀实践,具体落地时,仍然基于RPC的理念(以方法为中心)进行设计,方便HTTP跟RPC统一;

URL

定义:

  • 内部访问:http://{host}/{app}/[module]/{action}(实际action === method)
  • 外部访问:http://{host}/[product]/{app}/[module]/{action}(实际action === method)

名词解释:

  • host:主机名
  • product: 产品名 (可选,对外时使用,与微服务体系保持一致)
  • app:应用服务名 ,比如login,domainservice
  • module:资源模块名 (服务内部自由定义),可选(微服务本身有可能就只是一个模块,可省略,但建议设计一个模块名以防后面有新增模块,另外spring的拦截如果是/的话健康检查接口不是很好配置),如account,unit。
  • action:操作方法,建议与java方法名保持一致,方便搜索和定位,也可以采用中划线分隔不同单词,如getAccount, get-account,不要加.json, .do之类的后缀

示例:

http://service.qiye.163.com/reg/org/register?domain=xxx.com&orgName=小公司

约束:

  • 1,URL中除action外字母全部小写,中间可用’-‘分割(与服务名规范一致)
  • 2,如果有单词拼接,中间可用’-‘分割
  • 3,为了避免混淆,"/“不应该出现在URL的末尾
  • 4,URI中不要包含文件(脚本)的扩展名
  • 5,资源名是否为复数不做严格要求

注意:

如果走spring网关需要遵守网关的格式,具体请参考网关定义://TODO 网关说明链接

HTTP Method

遵从http协议规范,不增加额外的定义。

  • GET:查询,幂等操作;(只在查询时使用)
  • POST:新建,非幂等操作;(增加,删除,更新时使用)
  • PUT:完整替换,幂等操作;(不使用)
  • PATCH:特定更新,幂等操作;(协议标准为幂等,实际要看业务使用姿势,不使用)
  • DELETE:删除,幂等操作;(不使用)

请求参数

body:

优先使用json格式, 但特殊情况可以根据实现场景进行调整,在请求头的content-type中进行标明。

query:

参数中携带基本字段,方便日志输出,问题排场等(基本检索基于GET进行操作,复杂检索条件则走POST)

  • 基本query参数(待细化):
  • 基本header参数(待细化):NTES-TRACEID(traceid), CLIENT-VER(客户端版本), APP-VER(目标应用服务版本)
  • 分页:page(当前页数),offset(前面需要跳过的条目数,取值为(page-1)*limit),limit(当前需要返回的条目数),sort

响应码

前提:只要应用服务收到请求,并进入对应的处理函数,则可认为响应的HTTP Code为200!

  • HTTP CODE遵从http规范,不作变动。
  • Service CODE:
响应码 名称 含义
200 OK 请求成功,后端服务正常解析到请求,即认为是200,具体业务失败等,均有业务CODE区分。
3开头保留
400 BAD_REQUEST 非法请求,比如参数不合法
403 禁止访问,比如无权限
429 TOO_MANY_REQUEST 请求超额,此时可能是网关侧,也可能是服务端,如有需要通过具体描述区分
500 INTERNAL_SERVER_ERROR 服务器内部执行异常,具体需通过描述信息查看

备注:

1,对内接口,实际返回的描述信息可尽量详细,以方便业务定位; 2,对外接口,细节需要屏蔽,避免信息泄露,特别的,可以在网关侧进行统一管控;

响应消息

{
    code: 结果code
    msg:请求失败时的异常描述
    data:请求结果,要求是对象类型,不能是数组等其他数据类型,否则不容易后续扩展。
    desc:请求失败时的详细描述,一般供前端进行展示使用。
}
示例:
{
    code:200,
    data:
    {
        id:1023521,
        name:"myExample"
    }
}
分页查询时,返回如下:
{
    code:200,
    data:
    {
        page:直接取入参的值,
        offset:直接取入参的值,
        size:本次实际返回的条目数,
        result:[{...},{...}]
    }
}

安全性考虑

  • TLS加密;(最大程度防止抓包导致信息泄露,或者用户恶意伪造请求)
  • 业务加密;(TLS之上的,二次加密逻辑,提升安全性)
  • 时间戳;(防重复提交)
  • token;(身份验证)
  • 数据脱敏;(日志、运维检索等)
  • 敏感数据拉取的二次认证以及审计操作记录

性能考虑

对于耗时逻辑的接口调用,一方面可以做接口逻辑优化,另一方面可以考虑分拆为两次调用(prepare,do),模拟异步进行处理;

扩展

  • 1,接口版本更新:在header增加vxxx字段信息,默认就为最新版本;
  • 2,API规范性检查:增加API设计规范检查,从源头上进行统一;
  • 3,API接口定义工具,提升API设计效率;——将规则固化,将设计阶段纳入到DevOps流程中;
  • 4,幂等性考虑:创建、更新数据使用POST,非幂等;检索、删除数据使用GET,幂等;使用随机数作为参数,避免重复提交;

实践

  • 接口功能内聚,职责明确,避免混乱交叉、泛化通配的接口;(合理划分资源域,可基于DDD的思路进行领域层级的规划)
  • 接口数量控制,避免给用户带来负担;
  • 查询语句尽量使用GET(过于复杂的检索条件除外),数据更新必须使用POST;
  • Header中携带客户端版本等相关信息,方便进行数据的统计分析;
  • Header中携带traceid,结合日志输出,方便后续的链路跟踪排障;
  • URL最后的action名字,不同action之间不要有前缀包含关系;
  • 部分异常码可能只在内部使用,对外暴露时需要做一定的控制;
  • 异常场景下,考虑响应内容中增加具体接口的详细文档链接;
  • 检索响应数据字段的精细化管控:1)根据身份进行配置;2)根据场景通过额外字段指定(field参数指定 or GraphQL);
  • 内部运维接口操作的审核机制;(接口安全等级分级)
  • 内部运维数据查看的审核机制;(数据字段隐私分级)

能力建设

  • API文档(手动录入,工具生成)swagger –> nei
  • API管理(接口检索,文档查看,生命周期(开发,测试,发布))
  • API运维(流控,熔断等配置)
  • API统计(流量统计分析)
  • API监控(异常指标,风险监测)

演进

  • 随着微服务体系演进,进行扩展;(APM,日志,服务治理)
  • 基于API网关进行API的编排,简化外部调用;
  • 接口规范与具体传输协议分层,可以随着协议变更和演进;
  • 建设内外接口市场,进行接口维度的管控和治理;
  • OpenAPI的引入;
  • API管控能力交付给业务负责人;
  • 对于接口数量的控制,可以通过增加BFF层进行后端数据的聚合;(可以就是网关)

参考