API开放平台
API开放平台
项目介绍
做一个提供API接口调用的平台,用户可以注册登录,开通接口调用权限。用户可以使用接口,并且每次调用会进行统计。管理员可以发布接口、下线接口、接入接口,以及可视化接口的调用情况、数据
背景:
- 前端开发需要用到后台接口
- 使用现成的接口(https://api.btstu.cn/)
业务流程
做一个API接口平台
- 防止攻击(安全性)
- 不能随便调用(限制、开通)
- 计费
- 统计调用次数
- 流量保护
- API接入
1、SDK的外语全称是Software Development Kit,中文为:软件开发工具包,一般都是一些软件工程师为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件时的开发工具的集合;
2、可以将其理解为,由第三方服务商提供的实现软件产品某项功能的工具包,里面一般以集合kpi和文档、范例、工具的形式出现,也就是由很多类型文件的集合;
技术选型
前端
Ant Design Pro
React
Ant Design Procomoponents
Umi
Umi Request (Axios封装)
后端
Java Spring Boot
Spring Boot Starter(SDK开发)
???(网关、限流、日志实现)
项目计划
第一阶段
- 项目介绍、设计、技术选型
- 基础项目搭建
- 接口管理
- 用户查看接口
第二阶段
- 接口调用
- 接口文档展示、接口在线调用
- 保证调用的安全性(API签名认证)
- 客户端SDK的开发
第三阶段
- 统计用户调用次数
- 限流、计费、日志、开通
第四阶段
- 提供可视化平台,用图表的方式展示所有接口的调用情况,便于调整
- 自己实现:预警
需求分析
1、管理员可以对接口信息进行增删查改
2、用户可以访问前台,查看接口信息
数据库表设计
接口信息表
id
userId 创建人id
name 接口名称
description 描述
url 请求地址
method 请求类型
requestHeader 请求头
responseHeader 响应头
status 接口状态 0-关闭 1-开启
isDelete
creatTime
updateTime
使用其他类似的Controller进行快速开发(copy)
项目脚手架
前端:ant design pro脚手架
基础功能
增删查改、登录(以及校验)
前端接口调用:oneapi插件自动生成
openapi规范
第二期
模拟接口项目myapi-interface
提供三个模拟接口
- GET接口
- POST接口(url传参)
- POST接口(restful)
调用接口
几种HTTP调用方式:
- HttpClient
- RestTemplate
- 第三方库(OKHttp,Hutool)
https://hutool.cn/docs/#/http/Http%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%B7%A5%E5%85%B7%E7%B1%BB-HttpUtil
API 签名认证
本质:
- 签发签名
- 使用签名(校验)
为什么需要?
- 保证安全性,不能随便一个人调用
怎么实现?
通过http request header 头传递参数
参数1:accessKey: 调用标识 (复杂无序无规律)
参数2:secretKey: 密钥 (不放到请求头中)
(类比用户名和密码,区别:ak,sk是无状态的)
千万不能把密钥直接在服务器之间传递,也可能会被拦截
参数3:用户参数
参数4:sign
加密方式:对称加密、非对称加密、md5签名(不可逆)
用户参数: abc + 密钥 => 签名生成算法(MD5,Hmac) = > 不可解密的值
abc + abcdefg =》 osidjfoasipdf
那服务端怎么知道签名是否正确?
服务端用一模一样的参数和算法去生成签名,只要和用户传的一致,就表示一致。
怎么防重放?
参数5:加nonce 随机数,只能用一次
但服务端要保存用过的随机数
参数6:加一个timestamp 时间戳。校验时间戳是否过期。
API 签名认证是一个很灵活的设计,具体要有哪些参数、参数名如何一定要根据场景来。(比如userId、appId、version)
难道每次开发者调用接口都要自己写签名算法?
开发一个简单易用的SDK
理想情况:开发者只需要关心调用哪些接口,传递哪些参数,就跟调用自己写的代码一样。
开发starter的好处:
- 开发者引入后,可以直接在application.yml中写配置。自动创建客户端
自动生成代码提示
<dependency> |
// TODO 之后可以把打好的包上传到maven仓库
第三期
- 开发接口发布/下线的功能(管理员)
- 前端去浏览接口、查看接口文档、申请签名(注册)
- 在线调试(用户)
- 统计用户调用接口次数
- 优化系统-API网关
开发接口发布/下线功能(管理员)
后台接口:
发布接口:
- 校验接口是否存在
- 判断接口是否可用
- 修改接口数据库中状态字段为1
下线接口:
- 校验接口是否存在
- 修改接口数据库中状态字段为0
扩展:用户可以申请更换签名
在线调用
请求参数的类型(直接用JSON类型)
流程:
- 前端将用户输入的请求参数和要测试的接口id发给平台后端1
- 在调用前可以做一些校验
- 平台后端去调用模拟接口
TODO
- 判断该接口是否可以调用时,由固定方法名改为请求地址
- 用户测试接口也是这样优化
- 模拟接口改为从数据库校验 ak ,sk
第四阶段
- 开发接口调用次数的统计
- 优化整个系统的架构(API 网关)
- 网关是什么?
- 网关作用?
- 网关的应用场景以及实现
- 结合业务去应用网关
接口调用次数统计
需求:
- 用户每次调用接口成功,次数 + 1
- 给用户分配或用户自主申请接口调用次数
业务流程:
- 用户调用接口(之前已完成)
- 修改数据库,调用次数+1
设计库表
哪个用户?哪个接口?
用户 <=> 接口(N = N)
用户调用接口关系表:
|
开发增删查改功能给管理员
用户调用接口后次数加1
问题:
如果每个接口的方法都写调用次数+1,是不是比较麻烦?
致命问题:接口开发者需要自己去统计
- AOP
- 写一个通用方法,用到就调用
- servlet 拦截器
AOP,独立于接口,在每个接口调用后统计次数+1
缺点:只存在于单个项目中,如果每个团队都开发自己的模拟接口,都需要调用AOP所在的项目
网关
什么是网关?理解为门卫老大爷,需要统一经过审查才能进门。
网关优点:统一去进行一些操作、处理一些问题
作用
- 路由
- 负载均衡
- 鉴权
- 跨域
- 缓存
- 流量染色
- 访问控制
- 统一业务处理
- 发布控制
- 接口保护
- 限制请求
- 消息脱敏
- 降级(熔断)
- 限流: 学习令牌桶算法,学习redisRateLimiter
- 超时时间
- 统一日志
- 统一文档
路由
起到转发的作用,比如有接口a,接口b。网关会记录这些信息,根据用户访问的地址和参数,
转发请求到对应的接口(服务器/集群)
/a => interface a
/b => interface b
/c => interface c
断言路由 predicate
负载均衡
在路由的基础上
/c=> 服务a/集群a
统一鉴权
判断用户是否有权限进行操作。无论访问什么接口,我都去统一去判断权限,不用重复写。
统一跨域
网关统一处理跨一,不用在每个项目里单独处理
CORS Configuration :: Spring Cloud Gateway
统一业务处理
AOP plus版?
把一些项目中都要做的通用1逻辑放到上层(网关)。统一处理,例如本次的统计调用次数
访问控制
黑白名单,比如限制DDOS IP
发布控制
灰度发布,比如上线新接口,先给新接口分配20%的流量,然后慢慢调正比例
version1.0 version2.0 等2.0版本稳定后,逐渐给更多用户使用,然后逐渐覆盖迭代掉1.0
spring: |
流量染色
给请求(流量)添加一些标识,一般是设置请求头中,添加新的请求头。链路追踪
例如:
AddRequestHeader GatewayFilter Factory :: Spring Cloud Gateway
全局染色:
Default Filters :: Spring Cloud Gateway
统一接口保护
- 限制请求
- 消息脱敏
- 降级(熔断)
- 限流
- 超时时间
统一日志
统一的请求、响应信息记录
统一文档
将下游项目的文档进行聚合,方便管理查看
网关的分类
- 业务网关(微服务网关):作用是将请求转发到不同的业务/项目/接口/服务
- 全局网关(接入层网关):作用是负载均衡、请求日志等,不和业务逻辑绑定
实现
- Nginx (全局网关)\ Kong网关(API网关)
- SpringCloud GateWay( 取代了Zuul ) 性能高, 可以用Java代码写逻辑
https://zhuanlan.zhihu.com/p/500587132
Spring Cloud GateWay
Spring Cloud Gateway(demo)
核心概念
路由(根据说明条件,转发请求到哪里)
断言(一组规则或者条件,用来确定如何转发规则)
过滤器:对一系列请求或者响应进行处理,比如添加请求、请求参数
官方文档:
Spring Cloud Gateway :: Spring Cloud Gateway
两种配置方式
- 配置式(方便、规范)
- 简化版
- 全称
- 编程式(灵活、相对麻烦)
可以保护后台接口url
建议开启日志
|
断言有很多规则
- After
- Before
- …..
推荐自己先好好看看官方文档,知道大概有哪些东西。
顺便记得把simple demo看看
第五阶段:
- 实现统一的用户鉴权。把API网关应用到项目中
- 完善功能
要用到的特性
- 路由 (转发请求到模拟接口项目)
负载均衡- 鉴权 (accessKey,secretKey)
- 跨域 (看情况)
- 流量染色 (记录请求是否为网关来的)
- 访问控制 (黑白名单)
- 统一业务处理 (每次请求接口后次数+1)
发布控制- 接口保护
- 限制请求
- 消息脱敏
- 降级(熔断)
- 限流: 学习令牌桶算法、学习漏桶算法。学习redisRateLimiter
- 超时时间
- 统一日志 (记录每次的请求和响应日志)
- 统一文档
业务逻辑
用户发送请求到API网关
请求日志
(黑白名单)
用户鉴权,判断Ak,Sk是否合法
请求的模拟接口是否存在?
请求转发、调用模拟接口
响应日志
调用成功,调用次数加1
调用失败,返回一个规范的错误码
具体实现
1.请求转发
使用前缀匹配断言:
spring: |
所有路径为:/api/的请求进行转发。转发到 http ://localhost:8123/api/
比如请求:
http ://localhost:8090/api/name/get?name=moying
转发到
http ://localhost:8123/api/name/get?name=moying
2.全局过滤器
类似于AOP?建议看看流程图
|
因为网关项目没有引入Mybatis等操作数据库的类库,如果操作较为复杂,可以由backend增删查改项目提供接口,我们直接调用。就不用重复写逻辑了
- HTTP请求(用HTTPClient、RestTemplate、Feign、OpenFeign)
- RPC(Dubbo)
问题
预期是等模拟接口调用完成,才记录响应日志、统计调用次数
但是现实是chain.filter方法立刻返回了,直到filter过滤器return后才调用了模拟接口。
原因是:chain.filter是个异步操作?(看上面的流程图)
解决方案:利用二response装饰者,增强原有对象response的能力
第六阶段
计划
- 补充完整网关的业务逻辑(怎么去操作数据库、怎么复用之前的方法?RPC)
- 完善系统、开发一个监控统计功能
网关业务逻辑
问题:网关项目比较纯净、没有操作数据库的包、并且还要调用我们之前写过的代码,维护麻烦
理想:直接请求到其他项目的方法
怎么调用其他项目的方法
- 复制代码和依赖、环境
- HTTP请求(提供一个接口供其他项目调用)
- RPC
- 把公共的代码打个jar包,其他项目去引用(客户端SDK)
HTTP请求怎么调用
- 提供方开发一个接口(地址、请求方法、参数、返回值)
- 调用方使用HTTP client之类的代码包去发送HTTP请求
RPC
作用:像调用本地方法一样调用远程方法
对开发者来说更透明,减少了很多的沟通成本
RPC向远程服务器发送请求时,未必要使用HTTP协议。比如还可以用TCP/IP。性能更高(内部服务更适用)
https://blog.csdn.net/NF_ALONG/article/details/139506951
Dubbo框架 (RPC实现)
GRPC、TRPC
官方文档:
https://dubbo-next.staged.apache.org/zh-cn/overview/mannual/java-sdk/
两种方式:
- Springboot代码(注解——编程式): 写Java接口,服务提供者和消费者都去引用这个接口
- IDL(接口调用语言):创建一个公共的接口文件,服务提供者和消费者都去读取这个文件,主要是支持不同语言去使用
整合运用(Dubbo Nacos)
- backend作为服务提供者
- 实际情况是从数据库中查询secretKey
- 调用成功,调用次数加1
- 从数据库从查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数
- gateway项目作为服务调用者,调用这三个方法
注意:
- 服务接口类必须要在同一个包下,建议是抽象出一个公共项目(放接口、实体类等)
- 设置注解(比如启动类的EnableDubbo、接口实现类和Bean引用的注解)
- 添加配置
- 消费者和提供者尽量引入同样版本的配置和依赖
整合nacos:
https://dubbo-next.staged.apache.org/zh-cn/overview/reference/integrations/nacos/
moying-backend (7592)提供基础服务、用户登录、查询接口、上线接口、下线接口等。
myapi-client-sdk(指向8090) 提供接口服务,后续添加固定接口服务时在此扩展。
common公共模块,提供实体类,以及用户、调用接口校验的接口类。
myapi-gateway (8090,指向8123)网关。通过断言去转换请求地址,用户鉴权。
myapi-interface(8123) 接口实现?
大概流程,登录基础等操作在backend模块完成,此模块还提供inner服务接口(校验功能— >提供给网关)。
前端请求backend地址的服务。
使用invoke方法调用接口时,通过使用自制的sdk包装的请求。将请求地址转为gateway模块。
gateway模块接受到接口调用请求的时候,经过一系列处理和校验(通过tcp请求用户校验、接口校验、用户接口校验功能)后
通过断言转路由,将请求地址转给interface,在interface模块中写实际的接口功能。
最后返回结果。