API笔记

调用接口的几种方式

  1. HttpClient
  2. RestTemplate
  3. 第三方库(OKHTTP,hutool)

Hutool:https://loolly_admin.oschina.io/hutool-site/docs/#/

API签名认证

电影院看电影,不可能所有人都可以看电影,只允许有电影票的人看电影。

本质:

  1. 签发签名
  2. 使用签名(校验签名)

为什么需要API签名认证?

  1. 保证安全性,不能随便任何一个人调用

怎么实现?

参数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. 校验该接口是否存在
  2. 判断该接口是否可以调用
  3. 修改接口数据库中的状态字段为1

下线接口(仅管理员可操作)

  1. 校验该接口是否存在
  2. 修改接口数据库中的状态字段为0

判断该接口是否可以调用时由固定方法名改为测试地址来调用

前端去浏览接口(已完成)、查看接口文档(接口文档)

申请签名(注册)

用户在注册成功时,自动分配accessKey,secretKey

扩展点:用户可以申请更换签名

在线调用

请求参数的类型(直接用json)

1
2
3
[
{"name":"username", "type":"string"}
]

先跑通整个流程,再去针对不同的请求头或者接口类型来设计界面和表单,给用户更好的体验

Java 的 String 对应 JS 的 string

调用流程

流程:

  1. 前端将用户输入的请求参数和要测试的接口Id发给平台后端
  2. (在调用前可以做一些校验)
  3. 平台后端去调用模拟接口

todo

判断该接口是否可以调用时由固定方法改为根据测试地址来调用

用户测试接口固定方法改为根据测试地址来调用

第四期

  1. 开发接口调用次数的统计
  2. 优化整个系统的架构( API 网关)
  • 网关是什么?
  • 网关的作用
  • 网关的应用场景及实现
  • 结合业务应用网关

接口调用次数统计

需求:

  1. 用户每次调用接口成功,次数 + 1
  2. 给用户分配或者用户自主申请接口调用次数

业务流程:

  1. 用户调用接口(之前已完成)
  2. 修改数据库,调用次数 + 1

设计库表

哪个用户?哪个接口?

用户 => 接口(多对多关系)

用户接口关系表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
create table apicube.interface_info
(
id bigint auto_increment comment 'id'
primary key,
name varchar(256) not null comment '名称',
description varchar(256) null comment '描述',
url varchar(512) not null comment '接口地址',
requestHeader text null comment '请求头',
responseHeader text null comment '响应头',
status tinyint default 0 not null comment '接口状态 (0-关闭 1-开启)',
method varchar(128) not null comment '请求类型',
userId bigint null comment '创建人',
createTime datetime d efault *CURRENT_TIMESTAMP* not null comment '创建时间',
updateTime datetime default *CURRENT_TIMESTAMP* not null on update *CURRENT_TIMESTAMP* comment '更新时间',
isDelete int default 0 not null comment '是否删除'
)
comment '接口信息';

步骤:

  1. 开发基本增删改查(给管理员用)
  2. 开发用户调用接口次数 + 1的功能(Service层)

问题:如果每个接口的方法都写调用次数 + 1,是不是比较麻烦?致命问题:接口开发者需要自己去添加统计代码

使用AOP切面的优点:独立于每个接口,在每个接口调用后统计次数 + 1AOP 切面的缺点:只存在于单体项目,如果每个团队都要开发自己的模拟接口,那么都要写一个切面

网关

什么是网关?理解成火车站的检票口,统一去检票网关的优点:统一去进行一些操作、处理一些问题

网关作用

  1. 路由
  2. 鉴权
  3. 跨域
  4. 统一业务处理中(缓存)
  5. 流量染色
  6. 访问控制
  7. 统一业务处理
  8. 发布控制
  9. 脱敏
  10. 负载均衡
  11. 接口保护
  • 限制请求
  • 信息脱敏
  • 降级(熔断)
  • 限流
  • 超时时间
  1. 统一日志
  2. 统一文档

路由

起到转发的作用,比如有接口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/#the-weight-route-predicate-factory

流量染色

给请求(流量)添加一些标识,一般是设置在请求头中,添加新的请求头

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-addrequestheader-gatewayfilter-factory

全局染色https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#default-filters

统一接口保护

统一文档

将下游的文档进行聚合,在一个页面统一查看:doc.xiaominfo.com/docs/middleware-sources/aggregation-introduction

网关的分类

  1. 全局网关(接入层网关):层级更高,作用是负载均衡
  2. 业务网关(微服务网关):在项目/微服务之上,将请求转发到不同的业务 / 接口 / 服务

参考文章:https:/blog.csdn.net/qq21040559/article/details/122961395

实现

  1. Nginx(全局网关)、Kong 网关:https://github.com/Kong/Kong(API网关):编程成本较高
  2. 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/

核心概念

路由:(根据什么条件,转发请求到哪里)

断言:(一组规则 / 条件,用来确定如何转发路由)

过滤器:对请求进行一系列的处理,比如添加请求头、添加请求参数

请求流程:

  1. Gate Client客户端发起请求
  2. Gateway Handler Mapping:根据断言,将请求转发到对应的路由
  3. Gateway Web Handler:处理请求

img

两种配置方式

  1. 配置式(方便、规范)
  • 简化版
  • 全称版
  1. 编程式(灵活、相对麻烦)

断言

  1. After 在 xx 之后
  2. Before 在 xx 之前
  3. Between 在xx时间之间
  4. 请求类别
  5. 请求头(包含Cookie)
  6. 查询参数
  7. 客户端地址
  8. 权重

更改Spring Cloud Gateway输入出日志级别

1
2
3
4
5
6
logging:
level:
org:
springframework:
cloud:
gateway: trace

The DedupeResponseHeader GatewayFilter Factory:响应头去重,比如两个服务器都设置了跨域了,但有可能跨域失败,所以可能需要去重

过滤器

  1. 添加请求头
  2. 添加请求参数
  3. 添加响应头
  4. 降级
1
2
3
4
5
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
<version>2.1.7</version>
</dependency>

第五期

  1. 实现统一的用户鉴权、统一的接口调用次数统计(把 API 网关应用到项目中)
  2. 完善功能

要用到的特性

  1. 路由(转发请求到模拟接口项目)
负载均衡
  1. 统一鉴权(ak / sk)
  2. 跨域
  3. 统一业务处理(每次请求接口后,接口调用次数 +1)
  4. 访问控制(黑白名单,)
  5. 发布控制
  6. 流量染色
  7. 接口保护
  • 限制请求
  • 信息脱敏降级(熔断)
  • 限流
  • 限流:学习令牌桶算法、学习漏桶算法,学习一下RedisLimitHandler
  • 超时时间
  1. 统一日志(记录每次的请求和响应日志)
  2. 统一文档

业务逻辑

  1. 用户发送请求到 API 网关
  2. 请求日志
  3. (黑白名单)
  4. 用户鉴权(判断ak / sk 是否合法)
  5. 请求的模拟接口是否存在?
  6. 请求转发,调用模拟接口
  7. 调用成功,接口调用次数 +1
  8. 调用失败,返回一个规范的错误码
  9. 响应日志

具体实现

  1. 请求转发使用前缀匹配断言:
1
2
3
4
5
6
7
8
9
10
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=source, yupi
routes:
- id: api_route
uri: http://localhost:8123
predicates:
- Path=/api/**

所有路径为:/api/*的请求进行转发,转发到http:/localhost:8123/api/*比如请求网关:http://localhost:8090/api/name/get?name=yupi =>http://localhost:8123/api//name/get?name=yupi

  1. 编写业务逻辑自定义CustomGlobalFilter类实现GlobalFilter, Ordered接口因为网关项目没引入MyBatis等操作数据库的框架,如果该操作较为复杂,可以由backend 增删改查项目提供接口,不用再重写逻辑
  • HTTP请求(HttpClient、用RestTemplate、Feign)
  • RPC(Dubbo)
  1. 问题预期是等模拟接口调用完成,才记录响应日志、统计调用次数。但现实是 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

第六期

计划

  1. 补充完整网关的业务逻辑(怎么去操作数据库?怎么复用之前的方法?RPC)
  2. 完善系统、开发一个监控统计功能

网关业务逻辑

问题:网关项目比较纯净,没有操作数据库的包,并且还要调用我们之前写过的代码?复制粘贴和后期维护比较麻烦,理想:直接请求到其他项目的方法

怎么调用其他项目的方法

  1. 复制代码和依赖、环境
  2. HTTP请求(提供一个接口,供其他项目调用)
  3. RPC
  4. 把公共的代码打个jar包,其他项目去引用(客户端 SDK)

HTTP 请求怎么调用?

  1. 提供方开发一个接口(地址、请求方法、参数、返回值)
  2. 调用方使用HTTP Client之类的代码包去发送HTTP请求

RPC

作用:像调用本地方法一样调用远程方法。

  1. 对开发者更透明,减少了很多的沟通成本
  2. 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

两种使用方式:

  1. Spring Boot 代码(注解 + 编程式):写 Java 接口,服务提供者和消费者都去引用这个接口
  2. IDL (接口调用语言):创建一个公共的接口定义文件

Dubbo 底层是 Triple 协议

整合运用

  1. backend 项目作为服务提供者,提供3个方法
  • 实际情况应该是去数据库中查是否已分配该用户
  • 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
  • 调用成功,接口调用次数+1 invokeCount

整合 Nacos 注册中心:https://nacos.io/zh-cn/docs/use-nacos-with-dubbo.html

注意:

  1. 服务接口类必须要在同一个包下,建议是抽象出一个公共项目(放接口和实体类)
  2. 设置注解(比如启动类的@EnableDubbo、接口实现类和 Bean 引用的注解)
  3. 添加配置
  4. 解决依赖冲突(sl4j)
  5. 服务调用项目和提供者项目尽量引入想同的依赖和配置
1
2
3
4
5
6
7
8
9
10
11
<!--导入dubbo-starter-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.12</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.2.3</version>
</dependency>

第七期

  1. 完成网关业务逻辑
  2. 开发管理员分析功能
  3. 上线

网关业务逻辑

  1. 实际情况应该是去数据库中查是否已分配给用户秘钥(ak、sk是否合法)

  2. 先根据 ak 判断用户是否存在,查到 sk

  3. 对比 sk 和用户传的加密后的 sk 是否一致

  4. 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)

  5. todo 调用成功,接口调用次数+1 invokeCount

问题:如何获取接口转发服务器的地址

网关启动时,获取所有的接口信息,维护到内存的hashmap中;有请求时,根据请求的url路径或者其他参数(比如host 请求头)来判断应该转发到哪台服务器、以及用于校验接口是否存在

公共服务

目的是让方法、实体类在多个项目间复用、重复编写

  1. 数据库中查是否分配给用户( ak / sk,返回用户信息,为空表示不存在)
  2. 从数据库中查询模拟接口是否存在(请求路径、请求方法、请求参数,返回接口信息,为空表示不存在)
  3. 接口调用次数 + 1 invokeCount(ak、sk(标识用户),请求接口路径)
  4. 让服务提供者引入common包,测试是否正常运行
  5. 让服务消费者引入common包

开发统计分析

需求

各接口的总调用次数占比(饼图)取调用最多的前 3 个接口,从而分析出哪些接口没有人用(降低资源、或者下线),高频接口(增加资源、提高收费)

接口A:2次

接口B:3次

具体实现

前端

需求:展示饼图

推荐要用现成的库!!

ECharts(推荐)、Ant V、BizCharts

用法贼简单!

  1. 看官网
  2. 进入示例页面
  3. 找到你要的图
  4. 在线调试
  5. 复制代码
  6. 改为真实数据
后端

写一个接口,得到下列示例数据

接口A:2次

接口B:3次

  1. SQL 查询调用数据 select interfaceInfoId,sum(totalNum) as totalNum from user_interface_info group by interfaceInfoId order by totalNum desc limit 3
  2. 业务层去关联查询接口信息

扩展

  1. 怎么让其他用户也上传接口
  • 需要提供一个机制(界面),让用户输入自己接口的 host(服务器地址)、接口信息、并且遵循咱们的要求(并且使用咱们的 sdk)
  1. 在接入时,平台需要测试调用这个接口,保证其是正常的(在interfaceInfo 表中加个 host 字段,区分服务器地址)
  2. 网关判断调用者是否还有调用次数

上线

前端:参考之前用户中心或伙伴匹配系统的上线方式

后端:

  • backend项目:web项目,部署spring boot的jar包(对外的)
  • gateway网关项目:web项目,部署spring boot的jar包(对外的)
  • interface模拟接口项目:web项目,部署spring boot的jar包(不建议对外暴露的)

关键:网络必须要连通

如果自己学习用:单个服务器部署这三个项目就足够

如果你是搞大事,多个服务器建议在同一内网,内网交互会更快、且更安全