设计思路
# API
调用平台
# 项目介绍
一个提供 API
接口供开发者调用的平台。(类似腾讯云)
用户可以注册登录,开通接口调用权限。用户可以浏览接口并调用,且每次调用会进行统计。
管理员可以发布接口、下线接口、接入接口,以及可视化接口的调用情况、数据。
项目侧重于后端,包含较多的编程技巧和架构设计层面的知识。
# 第一阶段
# 主要内容:
- 项目介绍、业务流程、项目计划、需求分析
- 数据库表设计
- 前后端项目初始化(包含
Ant Design Pro
框架最新版本的使用) - 前后端代码自动生成(提高开发效率)
- 登录页、接口信息页开发
# 需求分析
背景:
前端开发需要用到后台接口
使用现成的系统的功能(博天api (opens new window))
做一个 API
接口平台:
- 管理员可以对接口信息进行增删改查
- 用户可以访问前台,查看接口信息
其他要求:
- 防止攻击(安全性)
- 不能随便调用(限制、开通) -- 限制流量,避免系统崩溃
- 统计调用次数
- 计费
- 流量保护
API
接入
# 业务流程
# 技术选型
# 前端
Ant Design Pro
React
Ant Design Procomponents
Umi
Umi Request
(Axios
的封装)
# 后端
Java Spring Boot
Spring Boot Starter
(SDK
开发)Dubbo
(RPC
)Nacos
Spring Cloud Gateway
(网关、限流、日志实现)
# 数据库表设计
-- 接口信息
create table if not exists myapi.`interface_info`
(
`id` bigint not null auto_increment comment '主键' primary key,
`name` varchar(256) not null comment '接口名称',
`description` varchar(256) null comment '描述',
`url` varchar(512) not null comment '接口地址',
`request_header` text null comment '请求头',
`reponse_header` text null comment '响应头',
`status` int default 0 not null comment '接口状态(0-关闭,1-开启))',
`method` varchar(256) not null comment '请求类型',
`user_id` bigint not null comment '创建人',
`create_time` datetime default CURRENT_TIMESTAMP not null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
`is_deleted` tinyint default 0 not null comment '是否删除(0-未删, 1-已删)'
) comment '接口信息';
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 项目脚手架
前端:Ant Design Pro
脚手架(https://pro.ant.design/zh-cn/)
后端:springboot-init
后端代码模板
# 基础功能开发
增删改查、登录功能(通过对模板的复制粘贴修改完成)
前端接口调用:后端使用遵循 openapi
的规范的 swagger
文档,使用前端 Ant Design Pro
框架集成的 openapi
插件自动生成。
# 第二阶段
# 主要内容:
- 开发接口管理前端页面
- 开发模拟
API
接口 - 开发调用接口客户端
- 开发调用的安全性(
API
签名认证) - 客户端
SDK
的开发(SDK
--Spring Boot Starter
开发)
# 模拟接口项目
项目名称:myapi-interface
提供三个不同种类的模拟接口:
GET
接口POST
接口(url
传参)POST
接口(Restful
)
# 调用接口
几种 HTTP
调用方式:
HttpClient
RestTemplate
- 第三方库(
OKHTTP
、Hutool
)
Hutool
:https://hutool.cn/docs/#/
HTTP
客户端工具类:
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
:调用的标识 userA
,userB
(复杂、无序、无规律)
参数 2:secretKey
:密钥(复杂、无序、无规律)该参数不能放到请求头中(类似用户名和密码,区别:ak
、sk
是无状态的)
可以自己写代码来给用户生成
ak
、sk
千万不能把密钥直接在服务器之间传递,有可能会被拦截
参数 3:用户请求参数
参数 4:sign
- 加密方式:对称加密、非对称加密、
md5
签名(不可解密) - 用户参数 + 密钥 => 签名生成算法(
MD5
、HMAac
、Sha1
) => 不可解密的值 abc + abcdefgh => sajdgdioajdgioa
怎么知道这个签名对不对?
服务端用一模一样的参数和算法去生成签名,只要和用户传的一致,就表示一致。
怎么防重放?
参数 5:加 nonce
随机数,只能用一次
服务端要保存用过的随机数(缺点:增大了开销,所以要给随机数加个有效期)
参数 6:加 timestamp
时间戳,校验时间戳是否过期。
API
签名认证是一个很灵活的设计,具体要有哪些参数、参数名如何一定要根据场景来。(比如 userId
、appId
、version
、固定值等)
思考:难道开发者每次调用接口都要自己写签名算法?
# 开发简单易用的 SDK
(简历加分项)
项目名:myapi-client-sdk
# 为什么需要 Starter
?
理想情况:开发者只需要关心调用哪些接口、传递哪些参数,就跟自己写的代码一样简单。
开发 starter
的好处:开发者引入之后,可以直接在 application.yml
中写配置,自动创建客户端
# Starter
开发流程
初始化,环境依赖(一定要移除 build
):
spring-boot-configuration-processor
的作用是自动生成配置的代码提示(yml
文件里)
<!--在 spring-boot-starter 依赖里包含了-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
编写配置类(启动类):
@Data
@ComponentScan
@Configuration
//定义一个配置前缀
@ConfigurationProperties(prefix = "chenmeng.api.client")
public class CmApiClientConfig {
private String accessKey;
private String secretKey;
@Bean
public CmApiClient cmApiClient() {
return new CmApiClient(accessKey, secretKey);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
注册配置类,resources/META_INF/spring.factories
文件:
# spring boot starter
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.chenmeng.CmApiClientConfig
2
mvn install
打包代码为本地依赖包
创建新项目,(复用 server
项目)、测试
小作业:把打包好的包发送到 maven
仓库中
# 第三阶段
# 主要内容:
- 开发接口发布 / 下线的功能
- 开发浏览接口、查看接口文档、申请签名功能
- 开发在线调试功能
# 功能开发
# 接口发布 / 下线的功能
权限控制:仅管理员操作
# 业务逻辑
发布接口:
- 校验该接口是否存在
- 判断该接口是否可以调用
- 修改接口数据库中的状态字段为 1(考虑:可以设计 0 为默认,1 为开启,2 为关闭)
下线接口:
- 校验该接口是否存在
- 修改接口数据库中的状态字段为 0
# 前端浏览接口
# 查看接口文档
思路:动态路由,用 url 来传递 id ,加载不同的接口信息
# 申请签名
用户在注册成功时,自动分配 accessKey、secretKey
# 在线调用
请求参数的类型(直接用 json 类型,更灵活):
[
{"name": "username", "type": "string"}
]
2
3
TODO
先跑通整个接口流程,后续可以针对不同的请求头或者接口类型来设计界面和表单,给用户更好的体验。(可以参考 swagger、postman、knife4j)
# 调用流程
使用上述流程:
流程:
- 前端将用户输入的请求参数和测试的接口 id 发给平台后端
- (在调用前可以做一些校验)
- 平台后端去调用模拟接口
# TODO
判断接口是否可以调用时 由固定方法名 改为根据测试地址来调用
用户测试接口固定方法名改为根据测试地址来调用
模拟接口改为数据库校验 aKey
给 请求参数的类型 加多个 type ,目前只有 name
# 第四阶段
# 主要内容:
- 开发接口调用次数统计功能
- 优化整个系统的架构 - API 网关详解
a. 网关是什么?
b. 网关的作用?
c. 网关的应用场景及实现?
d. 结合业务去应用网关
# 接口调用次数统计
需求:
- 用户每次调用接口成功,次数 +1 (可以考虑用 -1)
- 给用户分配或者用户自主申请接口调用次数
业务流程:
- 用户调用接口(之前已完成)
- 修改数据库,调用次数 +1
设计库表
用哪个用户?哪个接口?
用户 => 接口(多对多)
用户调用接口关系表:
--- 用户调用接口关系表
create table if not exists cmapi.`user_interface_info`
(
`id` bigint not null auto_increment comment '主键' primary key,
`userId` bigint not null comment '调用用户 id',
`interfaceInfoId` bigint not null comment '接口 id',
`totalNum` int default 0 not null comment '总调用次数',
`leftNum` int default 0 not null comment '剩余调用次数',
`status` int default 0 not null comment '0-正常,1-禁用',
`createTime` datetime default CURRENT_TIMESTAMP not null comment '创建时间',
`updateTime` datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
`isDelete` tinyint default 0 not null comment '是否删除(0-未删,1-已删)'
) comment '用户调用接口关系';
2
3
4
5
6
7
8
9
10
11
12
13
开发步骤:
- 开发基本增删改查(给管理员用)
- 开发用户调用接口次数 +1 的功能(service)
# 问题
如果每个接口的方法都调用次数 +1,是不是比较麻烦?
致命问题:接口开发者需要自己去添加统计代码
使用 AOP 切面的优点:独立于接口,在每个接口调用后统计次数 +1
使用 AOP 切面的缺点:只存在于单个项目中,如果每个团队都要开发自己模拟接口,那么都要写一个切面
# 网关
什么是网关?理解成火车站的检票口,统一去检票。
# 网关作用
统一去进行一些操作、处理一些问题。
比如:
路由
负载均衡
统一鉴权
跨域
统一业务处理(缓存也在这里处理)
访问控制
发布控制
流量染色
接口保护
a. 限制请求
b. 信息脱敏(操作请求头,响应头)
c. 降级(熔断)-- 请求某个接口时不成功,提示请求其它接口,兜底效果
d. 限流:学习令牌桶算法、学习漏桶算法,学习一下 RedisLimitHandler
e. 超时时间
统一日志
统一文档
具体作用
# 路由
起到转发的作用,比如有接口 A 和接口 B,网关会记录这些信息,根据用户访问的地址和参数,转发请求到对应的接口(服务器/集群)
/a => 接口 A
/b => 接口 B
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
# 负载均衡
在路由的基础上
/c => 服务A/集群A(随机转发到其中的某一机器)
uri 从固定地址改成 Ib:xxxx
# 统一鉴权
判断用户是否有权限进行操作,无论访问什么接口,我都统一去判断权限,不用重复写
# 统一处理跨域
网关统一处理跨域,不用在每个项目里单独处理
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration
# 统一业务处理
把每个项目中都要做的通用逻辑放到上层(网关),统一处理,比如本项目的次数统计
# 访问控制
黑白名单,比如限制DDOS IP
# 发布控制
灰度发布,比如上线新接口,先给新接口分配 20% 的流量,老接口 80%,再慢慢调整比重。(不同人的软件最新版不一样)
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
# 统一接口保护
限制请求
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#requestheadersiz-gatewayfilter-factory
信息脱敏
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-removerequestheader-gatewayfilter-factory
降级(熔断) 进行兜底
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#fallback-headers
限流
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-requestratelimiter-gatewayfilter-factory
超时时间 超时就中断
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#http-timeouts-configuration
重试(业务保护):
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-retry-gatewayfilter-factory
# 统一日志
统一的请求,响应信息记录
# 统一文档
将下游项目的文档进行聚合,在一个页面统一查看
建议用:https://doc.xiaominfo.com/docs/middleware-sources/aggregation-introduction
# 网关的分类
- **全局网关(接入层网关)**作用是负载均衡、请求日志等,不和业务逻辑绑定
- **业务网关(微服务网关)**会有一些业务逻辑,作用是将请求转发到不同的业务/项目/接口/服务
参考文章:https://blog.csdn.net/qq_21040559/article/details/122961395
# 网关实现
- Nginx (全局网关),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/
# 核心概念
路由 Route:(根据什么条件,转发请求到哪里)
断言 Predicate:一组规则、条件,用来确定如何转发路由
过滤器 Filter:对请求进行一系列的处理,比如添加请求头、添加请求参数
请求流程:
- 客户端发起请求
- Handler Mapping:根据断言,去将请求转发到对应的路由
- Web Handler:处理请求(一层层经过过滤器)
- 实际调用服务
# 两种配置方式
配置式(声明式,方便、规范)
a. 简化版
spring: cloud: gateway: routes: - id: after_route uri: https://example.org predicates: - Cookie=mycookie,mycookievalue
1
2
3
4
5
6
7
8b. 全称版
spring: cloud: gateway: routes: - id: after_route uri: https://example.org predicates: - name: Cookie args: name: mycookie regexp: mycookievalue
1
2
3
4
5
6
7
8
9
10
11编程式(灵活、相对麻烦)
# 建议开启日志
logging:
level:
org:
springframework:
cloud:
gateway: trace
2
3
4
5
6
# 断言
官网地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
目录:
- After 在 xx 时间之后
- Before 在 xx 时间之前
- Between 在 xx 时间之间
- 请求类别
- 请求头(包含 Cookie)
- 查询参数
- 客户端地址
- 权重
The After Route Predicate Factory
当前时间在这个时间之后,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
2
3
4
5
6
7
8
The Before Route Predicate Factory
当前时间在这个时间之前,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
2
3
4
5
6
7
8
The Between Route Predicate Factory
当前时间在这个时间之间,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
2
3
4
5
6
7
8
The Cookie Route Predicate Factory
如果你的请求头cookie的是chocolate,它的值是ch.p,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
2
3
4
5
6
7
8
The Header Route Predicate Factory
如果你的请求头包含X-Request-Id这样一个请求头,并且,它的值符合正则表达式的规则,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
2
3
4
5
6
7
8
The Host Route Predicate Factory
如果你的访问的是这个**.somehost.org,**.anotherhost.org,域名,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
2
3
4
5
6
7
8
The Method Route Predicate Factory
如果你的请求类别是这个GET、POST,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
2
3
4
5
6
7
8
9
The Path Route Predicate Factory
如果你的访问的地址是以这些**/red/{segment},/blue/{segment}**路径作为前缀,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
2
3
4
5
6
7
8
The Query Route Predicate Factory
根据查询条件,比如red greet green,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
2
3
4
5
6
7
8
The RemoteAddr Route Predicate Factory
根据远程地址,比如你的用户的ip地址是192.168.1.1/24,就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
2
3
4
5
6
7
8
The Weight Route Predicate Factory
根据你设置的权重,给你把同一个访问的地址,重定到不同的服务,轻松实现发布控制
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
2
3
4
5
6
7
8
9
10
11
12
The XForwarded Remote Addr Route Predicate Factory
从请求头中如果拿到XForwarded这个请求头的地址192.168.1.1/24 就会访问当前这个路由
spring:
cloud:
gateway:
routes:
- id: xforwarded_remoteaddr_route
uri: https://example.org
predicates:
- XForwardedRemoteAddr=192.168.1.1/24
2
3
4
5
6
7
8
# 过滤器
官网文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
基本功能:对请求头、请求参数、响应头的增删改查 1.添加清求头 2.添加请求参数 3.添加响应头 4.降级 5.限流 6.重试
引入依赖:
用于集成Reactor Resilience4j断路器库,以实现微服务的容错处理和服务熔断(接口保护 -- 降级)等功能。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
2
3
4
小作业:
通过阅读源码:https://spring.io/projects/spring-cloud-gateway/#samples 来了解gateway编程式开发
# 第五阶段
# 主要内容:
- 实现统一的接口鉴权和计费(API 网关实践)
实现统一的用户鉴权 ,统一的接口调用次数统计(把API网关用到项目中)
# 要用到的特性
- 路由(转发请求到模拟接口项目)
负载均衡(需要用到注册中心)- 统一鉴权(accessKey,secretKey)
- 统一处理跨域
- 统一业务处理(每次请求接口后,接口调用次数+1)
- 访问控制(黑白名单)
发布控制- 流量染色(记录请求是否为网关来的)
统一接口保护- 限制请求
- 信息脱敏
- 降级(熔断)
- 限流 学习令牌桶算法,学习露桶算法,学习一下RedislimitHandler
- 超时时间
- 重试(业务保护)
- 统一日志(记录每次的请求和响应)
统一文档
# 业务逻辑
用户发送请求到 API 网关
(面试官可能会问:为什么要用 API 网关?可以联想一下上面那个画图过程)
请求日志
(黑白名单)
用户鉴权(判断 ak、sk 是否合法)
请求的模拟接口是否存在?
请求转发,调用模拟接口
响应日志
调用成功,接口调用次数 + 1
调用失败,返回一个规范的错误码
# 具体实现
# 1、请求转发
使用 Path 前缀匹配断言:
将所有前缀为:/api/ 的请求进行转发,转发到http://localhost:8123/api
比如请求网关:localhost:8090/api/name/张三 (opens new window)转发到 localhost:8123/api/name/张三 (opens new window)
server:
port: 8090
spring:
cloud:
gateway:
routes:
- id: api_route
# 设置转发到哪个网址
uri: http://localhost:8123
# 前缀断言
predicates:
- Path=/api/**
2
3
4
5
6
7
8
9
10
11
12
13
# 2、编写业务逻辑
使用了 GlobalFilter(编程式,还有一种叫配置式,上面有讲),全局请求拦截处理(类似 AOP)
官网:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters
因为网关项目没引入 MyBatis 等操作数据库的类库,如果该操作较为复杂,可以由 backend 增删改查项目提供接口,我们直接调用,不用重复写逻辑了。
- HTTP 请求(用 HTTPClient、用 RestTemplate、Feign)
- RPC(Dubbo)
# 问题
预期等模拟接口调用完成,才记录响应日志、统计调用次数。
但现实是 chain.filter 方法立刻返回了,直到 filter 过滤器 return 后(此时已经记录了响应日志)才调用了模拟接口。
**原因是:**chain.filter 是个异步操作,理解为前端的 promise
**解决方案:**利用 response 装饰者,增强原有 response 的处理能力
参考博客:https://blog.csdn.net/qq_19636353/article/details/126759522(以这个为主)
其他参考:
- 网关 在GlobalFilter 拿出返回数据response (opens new window)
- SpringCloud-Gateway统一处理返回参数 (opens new window)
- 对请求参数解密,返回参数加密处理_springcloud 针对全局返回报文加密 (opens new window)
# 第六阶段
# 主要内容:
- 实现统一的接口鉴权和计费(RPC、Dubbo讲解)
# 网关业务逻辑
问题:网关项目比较存粹,没有操作数据库的包,并且还要调用我们之前写过的代码?复制粘贴维护麻烦 理想:直接请求到其他项目的方法
# 怎么调用其他项目的方法?
- 复制代码和依赖,环境
- HTTP请求(提供接口,供其他项目调用)
- RPC(Remote Procedure Call)远程过程调用
- 把公共的代码打个jar包,其他项目去引用
面试常问:HTTP 请求和 RPC 有什么区别
# HTTP 请求怎么调用?
- 提供方提供一个接口(地址,请求方法,参数,返回值)
- 调用方使用 HTTP Client 之类的代码包去发送 HTTP 请求
# RPC
作用:像调用本地方法一样去调用远程方法
和直接 HTTP 调用的区别,RPC 优点:
- 对开发者更透明,减少很多的沟通成本
- RPC 向远程服务器发送请求时,未必使用 HTTP 协议,比如还可以使用 TCP/IP,性能更高。(内部服务更实适用)
RPC 调用模型:
注意: 这里注册中心只提供信息,并不会帮助调用,实际调用还是提供者那边
# Dubbo 框架(RPC 实现)
其他 RPC 框架:GRPC、TRPC
最好的学习方式:阅读官方文档
https://dubbo.incubator.apache.org/zh/docs3-v2/java-sdk/quick-start/spring-boot/
# 两种使用方式
- Spring Boot代码(注解+编程式):写Java接口,服务提供者和消费者都去引用这个接口 偏程导
- DL(接口调用语言):创建一个公共的接口定义文件,服务提供者和消费者读取这个文件。优点是跨语言,所有的框架都认识
底层是Triple协议: https://dubbo.incubator.apache.org/zh/docs3-v2/java-sdk/concepts-and-architecture/triple/
# 官方的示例项目学习
zookeeper 注册中心:通过内嵌的方式运行,更方便
最先启动注册中心(EmbeddedZooKeeper,内嵌的注册中心),然后启动服务提供者(ProviderApplication),再启动服务消费者(ConsumerApplication)
# 整合运用
- backend项目作为服务提供者,提供3个方法:
- 实际情况应该是去数据库中查是否已分配给用户
- 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
- 调用成功,接口调用次数+1 invokeCount
- gateway项日作为服务调用者,调用这3个方法
zooKeeper 会有版本问题,解决起来比较麻烦
建议用 Nacos!
整合 Nacos 注册中心:https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/
注意:
- 服务接口类必须要在同一个包下,建议是抽象出一个公共项目(放接口、实体类等)
- 设置注解(比如启动类的 EnableDubbo、接口实现类和 Bean 引用的注解)
- 添加配置
- 服务调用项目和提供者项目尽量引入相同的依赖和配置
添加依赖
依赖从官方示例项目中复制粘贴过来的不行,要从 maven 仓库中找来相应的版本依赖
在 cmapi-backend、cmapi-gateway 中添加如下依赖
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.0.9</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.2.0</version>
</dependency>
2
3
4
5
6
7
8
9
10
11
# 第七阶段
# 主要内容:
- 开发抽象公共服务
- 实现网关核心业务流程
- 开发管理员接口分析功能
- 上线分析和扩展
# 梳理网关业务逻辑
以下操作可以复用:
- 去数据库中查是否已分配给用户秘钥(ak、sk 是否合法)
- 先根据 ak 判断用户是否存在,查到 secretKey
- 对比 sk 和用户传的加密后的 sk 是否一致
- 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
- 调用成功,接口调用次数+ 1 invokeCount
# 临时问题:如何获取接口转发服务器的地址
思路:网关启动时,获取所有的接口信息,维护到内存的 hashmap 中;有请求时,根据请求的 url 路径或者其他参数(比如 host 请求头)来判断应该转发到哪台服务器、以及用于校验接口是否存在
# 抽象公共服务
项目名: cmapi-common 目的是让方法、实体类在多个项目间复用,减少重复编写
服务抽取:
- 数据库中查是否已分配给用户秘钥 (根据 accessKey 拿到用户信息,返回用户信息,为空表示不存在)
- 从数据库中查询模拟接口是否存在(请求路径、请求方法、请求参数,返回接口信息,为空表示不存在)
- 接口调用次数 + 1invokeCount (accessKey、secretKey (标识用户),请求接口路径
步骤:
- 新建干净的 maven 项目,只保留必要的公共依赖
- 抽取 service 和实体类
- install 本地 maven 包
- 让服务提供者引入 common 包,测试是否正常运行
- 让服务消费者引入 common 包
# 统计分析功能
# 需求
各接口的总调用次数占比(饼图)取调用最多的前 3 个接口,从而分析出哪些接口没有人用(降低资源、或者下线),高频接口(增加资源、提高收费)用饼图展示。 Hs实现
# 前端
强烈推荐用现成的库!!! 比如:
- ECharts: https://echarts.apache.org/zh/index.html (推荐)
- AntV: https://antv.vision/zh (推荐)
- BizCharts
用法贼简单! 1.看官网 2。找到快速入门、按文档去引入库 3.进入示例页面 4。找到你要的图 5.在线调试 6.复制代码 7.改为真实数据
如果是 React 项目,用这个库: https://github.com/hustcc/echarts-for-react
# 后端
写一个接口,得到下列示例数据: 接口 A: 2次 接口 B: 3次
步骤: 1、SOL 查的调用数据: select interfacelnfold. sum/totalNum) as totalNum from user interface infogroup by interfacelnfold order by totalNum desc limit 3. 2、业务层去关联查询接口信息
# 上线计划
前端: 参考之前用户中心或伙伴匹配系统的上线方式 后端:
- backend 项目: web 项目,部署 spring boot 的jar 包(对外的)
- gateway 网关项目: web 项目,部署 spring boot 的jar 包 (对外的)interface 模拟接口项目: web 项目,部署 spring boot 的iar 包(建议对外暴露的)
关键: 网络必须要连通 如果自己学习用: 单个服务器部署这三个项目就足够
如果你是搞大事,多个服务器建议在 同一内网,内网交互会更快、且更安全
# 扩展思路
1. 用户可以申请更换签名
2. 怎么让其他用户也上传接口?
需要提供一个机制(界面),让用户输入自己的接口 host (服务器地址) 、接口信息,将接口信息写入数据库。可以在 interfacelnfo 表里加个 host 字段,区分服务器地址,让接口提供者更灵活地接入系统。
将接口信息写入数据库之前,要对接口进行校验(比如检查他的地址是否遵循规则,测试调用),保证他是正常的。
将接口信息写入数据库之前遵循咱们的要求(并且使用咱们的 sdk),
在接入时,平台需要测试调用这个接口,保证他是正常的。
3. 网关校验是否还有调用次数 需要考虑并发问题,防止瞬间调用超额
4. 网关优化 比如增加限流/降级保护,提高性能等。还可以考搭配 Nginx 网关使用。
5. 功能增强 可以针对不同的请求头或者接口类型来设计前端界面和表单,便于用户调用,获得更好的体验。可以参考 swagger、postman、knife4j 的页面