API 项目笔记
API笔记
调用接口的几种方式
- HttpClient
- RestTemplate
- 第三方库(OKHTTP,hutool)
Hutool:https://loolly_admin.oschina.io/hutool-site/docs/#/
API签名认证
电影院看电影,不可能所有人都可以看电影,只允许有电影票的人看电影。
本质:
- 签发签名
- 使用签名(校验签名)
为什么需要API签名认证?
- 保证安全性,不能随便任何一个人调用
怎么实现?
参数1:accessKey:调用的标识userA,userB(复杂、无序、无规律)
参数2:secretKey:密钥(复杂、无序、无规律 【该参数不放在请求头中】)
(类似用户名和密码,区别:ak、sk是无状态)
千万不能把密钥直接放在服务端或者服务器之间传递,有可能会被拦截
加密方式:对称加密、非对称加密、md5加密(不可解密)
参数3:用户参数 + 密钥 + => 签名生成算法(MD5,HMac、Sha1) => 不可解密的值
参数4:sign
abc + abcdefg => dnjwkdhnwji
怎么知道这个签名是否对不对?服务端用一模一样的参数和算法去生成签名只要知用户传的一致,就表示一致
怎么防重放?
参数5:加nonce随机数,只能用一次,但是服务端要保存用过的随机数
参数6:加timestamp时间戳
API签名认证是一个很灵活的设计,具体要有哪些参数、参数名如何一定要根据场景来。(比如userld、appld、version、.固定值等)
思考:难道开发者每次调用接口都要自己写签名算法?
开发一个简易的SDK(简历加分项)
理想情况:开发者只需要关心调用哪些接口、传递哪些参数,就跟调用自己写的代码一样简单。
spring-boot-configuration-processor的作用是自动生成配置的代码提示
开发接口发布/下线的功能(管理员)20min
后台接口:
发布接口(仅管理员可操作)
- 校验该接口是否存在
- 判断该接口是否可以调用
- 修改接口数据库中的状态字段为1
下线接口(仅管理员可操作)
- 校验该接口是否存在
- 修改接口数据库中的状态字段为0
判断该接口是否可以调用时由固定方法名改为测试地址来调用
前端去浏览接口(已完成)、查看接口文档(接口文档)
申请签名(注册)
用户在注册成功时,自动分配accessKey,secretKey
扩展点:用户可以申请更换签名
在线调用
请求参数的类型(直接用json)
1 | [ |
先跑通整个流程,再去针对不同的请求头或者接口类型来设计界面和表单,给用户更好的体验
Java 的 String 对应 JS 的 string
调用流程
流程:
- 前端将用户输入的请求参数和要测试的接口Id发给平台后端
- (在调用前可以做一些校验)
- 平台后端去调用模拟接口
todo
判断该接口是否可以调用时由固定方法改为根据测试地址来调用
用户测试接口固定方法改为根据测试地址来调用
第四期
- 开发接口调用次数的统计
- 优化整个系统的架构( API 网关)
- 网关是什么?
- 网关的作用
- 网关的应用场景及实现
- 结合业务应用网关
接口调用次数统计
需求:
- 用户每次调用接口成功,次数 + 1
- 给用户分配或者用户自主申请接口调用次数
业务流程:
- 用户调用接口(之前已完成)
- 修改数据库,调用次数 + 1
设计库表
哪个用户?哪个接口?
用户 => 接口(多对多关系)
用户接口关系表:
1 | create table apicube.interface_info |
步骤:
- 开发基本增删改查(给管理员用)
- 开发用户调用接口次数 + 1的功能(Service层)
问题:如果每个接口的方法都写调用次数 + 1,是不是比较麻烦?致命问题:接口开发者需要自己去添加统计代码
使用AOP切面的优点:独立于每个接口,在每个接口调用后统计次数 + 1AOP 切面的缺点:只存在于单体项目,如果每个团队都要开发自己的模拟接口,那么都要写一个切面
网关
什么是网关?理解成火车站的检票口,统一去检票网关的优点:统一去进行一些操作、处理一些问题
网关作用
- 路由
- 鉴权
- 跨域
- 统一业务处理中(缓存)
- 流量染色
- 访问控制
- 统一业务处理
- 发布控制
- 脱敏
- 负载均衡
- 接口保护
- 限制请求
- 信息脱敏
- 降级(熔断)
- 限流
- 超时时间
- 统一日志
- 统一文档
路由
起到转发的作用,比如有接口A和接口B,网关会记录这些信息,根据用户访问的地址和参数,转发请求到对应接口 / 服务器 / 集群/a ==> 接口A
/b ==> 接口B
负载均衡
在路由的基础上
/c => 服务A / 集群A(随机转发到其中的某一个机器中)
统一鉴权
判断用户是否有权限进行操作,无论访问什么接口,我都统一去判断权限,不用重复写。
网关统一处理跨域
网关统一处理跨域,不用每个项目里处理跨域问题
统一业务处理(缓存)
把一些每个项目中都要做的通用逻辑放在上层(网关),统一处理。比如本项目的接口调用次数统计
访问控制
黑名单中,比如限制DDOS IP
发布控制
灰度发布,比如上线新接口,先给新接口分配20%的流量,老接口80%,再慢慢调整比重。
接口A 和接口A V2,接口A V2刚上线,分配80%流量给接口A,分配20%流量给接口A V2,等到接口A V2没问题了,在将接口A下线并流程全部分配给接口A V2
流量染色
给请求(流量)添加一些标识,一般是设置在请求头中,添加新的请求头
全局染色:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#default-filters
统一接口保护
- 限制请求
- 信息脱敏(抹去响应头中的IP地址)
- 降级(熔断)
- 限流
- 超时时间
- 重试(业务保护):https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-retry-gatewayfilter-factory
统一文档
将下游的文档进行聚合,在一个页面统一查看:doc.xiaominfo.com/docs/middleware-sources/aggregation-introduction
网关的分类
- 全局网关(接入层网关):层级更高,作用是负载均衡
- 业务网关(微服务网关):在项目/微服务之上,将请求转发到不同的业务 / 接口 / 服务
参考文章:https:/blog.csdn.net/qq21040559/article/details/122961395
实现
- Nginx(全局网关)、Kong 网关:https://github.com/Kong/Kong(API网关):编程成本较高
- Spring Cloud Gateway(取代了Zuul):性能高,可以用Java代码编写逻辑,适于学习
网关技术选型:https://zhuanlan.zhihu.com/p/500587132
Spring Cloud Gateway 用法
去看官网:https://spring.io/projects/spring-cloud-gateway
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
核心概念
路由:(根据什么条件,转发请求到哪里)
断言:(一组规则 / 条件,用来确定如何转发路由)
过滤器:对请求进行一系列的处理,比如添加请求头、添加请求参数
请求流程:
- Gate Client客户端发起请求
- Gateway Handler Mapping:根据断言,将请求转发到对应的路由
- Gateway Web Handler:处理请求
两种配置方式
- 配置式(方便、规范)
- 简化版
- 全称版
- 编程式(灵活、相对麻烦)
断言
- After 在 xx 之后
- Before 在 xx 之前
- Between 在xx时间之间
- 请求类别
- 请求头(包含Cookie)
- 查询参数
- 客户端地址
- 权重
更改Spring Cloud Gateway输入出日志级别
1 | logging: |
The DedupeResponseHeader GatewayFilter Factory:响应头去重,比如两个服务器都设置了跨域了,但有可能跨域失败,所以可能需要去重
过滤器
- 添加请求头
- 添加请求参数
- 添加响应头
- 降级
1 | <dependency> |
第五期
- 实现统一的用户鉴权、统一的接口调用次数统计(把 API 网关应用到项目中)
- 完善功能
要用到的特性
- 路由(转发请求到模拟接口项目)
负载均衡
- 统一鉴权(ak / sk)
- 跨域
- 统一业务处理(每次请求接口后,接口调用次数 +1)
- 访问控制(黑白名单,)
- 发布控制
- 流量染色
- 接口保护
- 限制请求
- 信息脱敏降级(熔断)
- 限流
- 限流:学习令牌桶算法、学习漏桶算法,学习一下RedisLimitHandler
- 超时时间
- 统一日志(记录每次的请求和响应日志)
- 统一文档
业务逻辑
- 用户发送请求到 API 网关
- 请求日志
- (黑白名单)
- 用户鉴权(判断ak / sk 是否合法)
- 请求的模拟接口是否存在?
- 请求转发,调用模拟接口
- 调用成功,接口调用次数 +1
- 调用失败,返回一个规范的错误码
- 响应日志
具体实现
- 请求转发使用前缀匹配断言:
1 | spring: |
所有路径为:/api/*的请求进行转发,转发到http:/localhost:8123/api/*比如请求网关:http://localhost:8090/api/name/get?name=yupi =>http://localhost:8123/api//name/get?name=yupi
- 编写业务逻辑自定义CustomGlobalFilter类实现GlobalFilter, Ordered接口因为网关项目没引入MyBatis等操作数据库的框架,如果该操作较为复杂,可以由backend 增删改查项目提供接口,不用再重写逻辑
- HTTP请求(HttpClient、用RestTemplate、Feign)
- RPC(Dubbo)
- 问题预期是等模拟接口调用完成,才记录响应日志、统计调用次数。但现实是 chain.filter 方法立刻返回了,直到 filter 过滤器 return 后才调用了模拟接口。愿意是:chain.filter 是个异步操作参考博客:http://t.csdnimg.cn/v5PRN**其他参考:**https://blog.csdn.net/m0_67595943/article/details/124667975https://blog.csdn.net/weixin_43933728/article/details/121359727https://blog.csdn.net/zx156955/article/details/121670681https://blog.csdn.net/qq_39529562/article/details/108911983
第六期
计划
- 补充完整网关的业务逻辑(怎么去操作数据库?怎么复用之前的方法?RPC)
- 完善系统、开发一个监控统计功能
网关业务逻辑
问题:网关项目比较纯净,没有操作数据库的包,并且还要调用我们之前写过的代码?复制粘贴和后期维护比较麻烦,理想:直接请求到其他项目的方法
怎么调用其他项目的方法
- 复制代码和依赖、环境
- HTTP请求(提供一个接口,供其他项目调用)
- RPC
- 把公共的代码打个jar包,其他项目去引用(客户端 SDK)
HTTP 请求怎么调用?
- 提供方开发一个接口(地址、请求方法、参数、返回值)
- 调用方使用HTTP Client之类的代码包去发送HTTP请求
RPC
作用:像调用本地方法一样调用远程方法。
- 对开发者更透明,减少了很多的沟通成本
- RPC 向远程服务器发送请求时,未必要使用HTTP协议,比如还可以用 TCP / IP,性能更高。(内部服务更适用)
RPC:调用过程:
Dubbo 框架(RPC实现)
GRPC(Google)、TRPC(Tencent)
官方文档:https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/quick-start/spring-boot/
实例项目学习:https://github.com/apache/dubbo-samples IDEA 打开1-basic/dubbo-samples-spring-boot
两种使用方式:
- Spring Boot 代码(注解 + 编程式):写 Java 接口,服务提供者和消费者都去引用这个接口
- IDL (接口调用语言):创建一个公共的接口定义文件
Dubbo 底层是 Triple 协议
整合运用
- backend 项目作为服务提供者,提供3个方法
- 实际情况应该是去数据库中查是否已分配该用户
- 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
- 调用成功,接口调用次数+1 invokeCount
整合 Nacos 注册中心:https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html
注意:
- 服务接口类必须要在同一个包下,建议是抽象出一个公共项目(放接口和实体类)
- 设置注解(比如启动类的@EnableDubbo、接口实现类和 Bean 引用的注解)
- 添加配置
- 解决依赖冲突(sl4j)
- 服务调用项目和提供者项目尽量引入想同的依赖和配置
1 | <!--导入dubbo-starter--> |
第七期
- 完成网关业务逻辑
- 开发管理员分析功能
- 上线
网关业务逻辑
实际情况应该是去数据库中查是否已分配给用户秘钥(ak、sk是否合法)
先根据 ak 判断用户是否存在,查到 sk
对比 sk 和用户传的加密后的 sk 是否一致
从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
todo 调用成功,接口调用次数+1 invokeCount
问题:如何获取接口转发服务器的地址
网关启动时,获取所有的接口信息,维护到内存的hashmap中;有请求时,根据请求的url路径或者其他参数(比如host 请求头)来判断应该转发到哪台服务器、以及用于校验接口是否存在
公共服务
目的是让方法、实体类在多个项目间复用、重复编写
- 数据库中查是否分配给用户( ak / sk,返回用户信息,为空表示不存在)
- 从数据库中查询模拟接口是否存在(请求路径、请求方法、请求参数,返回接口信息,为空表示不存在)
- 接口调用次数 + 1 invokeCount(ak、sk(标识用户),请求接口路径)
- 让服务提供者引入common包,测试是否正常运行
- 让服务消费者引入common包
开发统计分析
需求
各接口的总调用次数占比(饼图)取调用最多的前 3 个接口,从而分析出哪些接口没有人用(降低资源、或者下线),高频接口(增加资源、提高收费)
接口A:2次
接口B:3次
具体实现
前端
需求:展示饼图
推荐要用现成的库!!
ECharts(推荐)、Ant V、BizCharts
用法贼简单!
- 看官网
- 进入示例页面
- 找到你要的图
- 在线调试
- 复制代码
- 改为真实数据
后端
写一个接口,得到下列示例数据
接口A:2次
接口B:3次
- SQL 查询调用数据 select interfaceInfoId,sum(totalNum) as totalNum from user_interface_info group by interfaceInfoId order by totalNum desc limit 3
- 业务层去关联查询接口信息
扩展
- 怎么让其他用户也上传接口
- 需要提供一个机制(界面),让用户输入自己接口的 host(服务器地址)、接口信息、并且遵循咱们的要求(并且使用咱们的 sdk)
- 在接入时,平台需要测试调用这个接口,保证其是正常的(在interfaceInfo 表中加个 host 字段,区分服务器地址)
- 网关判断调用者是否还有调用次数
上线
前端:参考之前用户中心或伙伴匹配系统的上线方式
后端:
- backend项目:web项目,部署spring boot的jar包(对外的)
- gateway网关项目:web项目,部署spring boot的jar包(对外的)
- interface模拟接口项目:web项目,部署spring boot的jar包(不建议对外暴露的)
关键:网络必须要连通
如果自己学习用:单个服务器部署这三个项目就足够
如果你是搞大事,多个服务器建议在同一内网,内网交互会更快、且更安全