沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • 脚手架搭建
  • 瑞吉外卖

  • 黑马点评

  • vue-blog

  • 沉梦接口开放平台

    • 设计思路
      • 项目介绍
      • 第一阶段
        • 主要内容:
        • 需求分析
        • 业务流程
        • 技术选型
        • 前端
        • 后端
        • 数据库表设计
        • 项目脚手架
        • 基础功能开发
      • 第二阶段
        • 主要内容:
        • 模拟接口项目
        • 调用接口
        • API 签名认证
        • 签名认证实现
        • 开发简单易用的 SDK(简历加分项)
        • 为什么需要 Starter?
        • Starter 开发流程
      • 第三阶段
        • 主要内容:
        • 功能开发
        • 接口发布 / 下线的功能
        • 业务逻辑
        • 前端浏览接口
        • 查看接口文档
        • 申请签名
        • 在线调用
        • 调用流程
        • TODO
      • 第四阶段
        • 主要内容:
        • 接口调用次数统计
        • 问题
        • 网关
        • 网关作用
        • 路由
        • 负载均衡
        • 统一鉴权
        • 统一处理跨域
        • 统一业务处理
        • 访问控制
        • 发布控制
        • 流量染色
        • 统一接口保护
        • 统一日志
        • 统一文档
        • 网关的分类
        • 网关实现
        • Spring Cloud Gateway 用法
        • 核心概念
        • 两种配置方式
        • 建议开启日志
        • 断言
        • 过滤器
      • 第五阶段
        • 主要内容:
        • 要用到的特性
        • 业务逻辑
        • 具体实现
        • 1、请求转发
        • 2、编写业务逻辑
        • 问题
      • 第六阶段
        • 主要内容:
        • 网关业务逻辑
        • 怎么调用其他项目的方法?
        • HTTP 请求怎么调用?
        • RPC
        • Dubbo 框架(RPC 实现)
        • 两种使用方式
        • 官方的示例项目学习
        • 整合运用
      • 第七阶段
        • 主要内容:
        • 梳理网关业务逻辑
        • 临时问题:如何获取接口转发服务器的地址
        • 抽象公共服务
        • 统计分析功能
        • 需求
        • 前端
        • 后端
        • 上线计划
        • 扩展思路
    • 笔记
  • 用户中心

  • 聚合搜索平台

  • 仿12306项目

  • 壁纸小程序项目

  • RuoYi-Vue

  • 项目笔记
  • 沉梦接口开放平台
沉梦听雨
2023-06-08
目录

设计思路

# API 调用平台

# 项目介绍

一个提供 API 接口供开发者调用的平台。(类似腾讯云)

用户可以注册登录,开通接口调用权限。用户可以浏览接口并调用,且每次调用会进行统计。

管理员可以发布接口、下线接口、接入接口,以及可视化接口的调用情况、数据。

项目侧重于后端,包含较多的编程技巧和架构设计层面的知识。

# 第一阶段

# 主要内容:

  1. 项目介绍、业务流程、项目计划、需求分析
  2. 数据库表设计
  3. 前后端项目初始化(包含 Ant Design Pro 框架最新版本的使用)
  4. 前后端代码自动生成(提高开发效率)
  5. 登录页、接口信息页开发

# 需求分析

背景:

  1. 前端开发需要用到后台接口

  2. 使用现成的系统的功能(博天api (opens new window))

做一个 API 接口平台:

  1. 管理员可以对接口信息进行增删改查
  2. 用户可以访问前台,查看接口信息

其他要求:

  1. 防止攻击(安全性)
  2. 不能随便调用(限制、开通) -- 限制流量,避免系统崩溃
  3. 统计调用次数
  4. 计费
  5. 流量保护
  6. API 接入

# 业务流程

image-20230424200930707

# 技术选型

# 前端

  • 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 '接口信息';
1
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 插件自动生成。

# 第二阶段

# 主要内容:

  1. 开发接口管理前端页面
  2. 开发模拟 API 接口
  3. 开发调用接口客户端
  4. 开发调用的安全性(API 签名认证)
  5. 客户端 SDK 的开发(SDK--Spring Boot Starter 开发)

# 模拟接口项目

项目名称:myapi-interface

提供三个不同种类的模拟接口:

  1. GET 接口
  2. POST 接口(url 传参)
  3. POST 接口(Restful)

# 调用接口

几种 HTTP 调用方式:

  1. HttpClient
  2. RestTemplate
  3. 第三方库(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 签名认证

本质:

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

为什么需要?

  1. 保证安全性,不能随便一个人调用
  2. 适用于无需保存登录态的场景。只认签名,不关注用户登录态。

# 签名认证实现

通过 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>
1
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);
    }

}
1
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
1
2

mvn install 打包代码为本地依赖包

创建新项目,(复用 server 项目)、测试

小作业:把打包好的包发送到 maven 仓库中

# 第三阶段

# 主要内容:

  1. 开发接口发布 / 下线的功能
  2. 开发浏览接口、查看接口文档、申请签名功能
  3. 开发在线调试功能

# 功能开发

# 接口发布 / 下线的功能

权限控制:仅管理员操作

# 业务逻辑

发布接口:

  1. 校验该接口是否存在
  2. 判断该接口是否可以调用
  3. 修改接口数据库中的状态字段为 1(考虑:可以设计 0 为默认,1 为开启,2 为关闭)

下线接口:

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

# 前端浏览接口

# 查看接口文档

思路:动态路由,用 url 来传递 id ,加载不同的接口信息

# 申请签名

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

# 在线调用

请求参数的类型(直接用 json 类型,更灵活):

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

TODO

先跑通整个接口流程,后续可以针对不同的请求头或者接口类型来设计界面和表单,给用户更好的体验。(可以参考 swagger、postman、knife4j)

# 调用流程

使用上述流程:

image-20230503194855075

流程:

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

# TODO

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

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

模拟接口改为数据库校验 aKey

给 请求参数的类型 加多个 type ,目前只有 name

# 第四阶段

# 主要内容:

  1. 开发接口调用次数统计功能
  2. 优化整个系统的架构 - API 网关详解

​ a. 网关是什么?

​ b. 网关的作用?

​ c. 网关的应用场景及实现?

​ d. 结合业务去应用网关

# 接口调用次数统计

需求:

  1. 用户每次调用接口成功,次数 +1 (可以考虑用 -1)
  2. 给用户分配或者用户自主申请接口调用次数

业务流程:

  1. 用户调用接口(之前已完成)
  2. 修改数据库,调用次数 +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 '用户调用接口关系';
1
2
3
4
5
6
7
8
9
10
11
12
13

开发步骤:

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

# 问题

如果每个接口的方法都调用次数 +1,是不是比较麻烦?

致命问题:接口开发者需要自己去添加统计代码

image-20230506174904962

  • 使用 AOP 切面的优点:独立于接口,在每个接口调用后统计次数 +1

  • 使用 AOP 切面的缺点:只存在于单个项目中,如果每个团队都要开发自己模拟接口,那么都要写一个切面

# 网关

什么是网关?理解成火车站的检票口,统一去检票。

# 网关作用

统一去进行一些操作、处理一些问题。

比如:

  1. 路由

  2. 负载均衡

  3. 统一鉴权

  4. 跨域

  5. 统一业务处理(缓存也在这里处理)

  6. 访问控制

  7. 发布控制

  8. 流量染色

  9. 接口保护

    a. 限制请求

    b. 信息脱敏(操作请求头,响应头)

    c. 降级(熔断)-- 请求某个接口时不成功,提示请求其它接口,兜底效果

    d. 限流:学习令牌桶算法、学习漏桶算法,学习一下 RedisLimitHandler

    e. 超时时间

  10. 统一日志

  11. 统一文档

具体作用

# 路由

起到转发的作用,比如有接口 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

# 统一接口保护
  1. 限制请求

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

  2. 信息脱敏

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

  3. 降级(熔断) 进行兜底

    https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#fallback-headers

  4. 限流

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

  5. 超时时间 超时就中断

    https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#http-timeouts-configuration

  6. 重试(业务保护):

    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

# 网关实现

  1. Nginx (全局网关),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/

# 核心概念

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

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

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

请求流程:

  1. 客户端发起请求
  2. Handler Mapping:根据断言,去将请求转发到对应的路由
  3. Web Handler:处理请求(一层层经过过滤器)
  4. 实际调用服务

image-20230509171132036

# 两种配置方式

  1. 配置式(声明式,方便、规范)

    a. 简化版

    spring:
      cloud:
        gateway:
          routes:
          - id: after_route
            uri: https://example.org
            predicates:
            - Cookie=mycookie,mycookievalue
    
    1
    2
    3
    4
    5
    6
    7
    8

    b. 全称版

    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
  2. 编程式(灵活、相对麻烦)

# 建议开启日志

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

# 断言

官网地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

目录:

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

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]
1
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]
1
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]
1
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
1
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+
1
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
1
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

1
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}
1
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.
1
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
1
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
1
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
1
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>
1
2
3
4

小作业:

通过阅读源码:https://spring.io/projects/spring-cloud-gateway/#samples 来了解gateway编程式开发

# 第五阶段

# 主要内容:

  1. 实现统一的接口鉴权和计费(API 网关实践)

实现统一的用户鉴权 ,统一的接口调用次数统计(把API网关用到项目中)

# 要用到的特性

  1. 路由(转发请求到模拟接口项目)
  2. 负载均衡(需要用到注册中心)
  3. 统一鉴权(accessKey,secretKey)
  4. 统一处理跨域
  5. 统一业务处理(每次请求接口后,接口调用次数+1)
  6. 访问控制(黑白名单)
  7. 发布控制
  8. 流量染色(记录请求是否为网关来的)
  9. 统一接口保护
    1. 限制请求
    2. 信息脱敏
    3. 降级(熔断)
    4. 限流 学习令牌桶算法,学习露桶算法,学习一下RedislimitHandler
    5. 超时时间
    6. 重试(业务保护)
  10. 统一日志(记录每次的请求和响应)
  11. 统一文档

# 业务逻辑

  1. 用户发送请求到 API 网关

    (面试官可能会问:为什么要用 API 网关?可以联想一下上面那个画图过程)

  2. 请求日志

  3. (黑白名单)

  4. 用户鉴权(判断 ak、sk 是否合法)

  5. 请求的模拟接口是否存在?

  6. 请求转发,调用模拟接口

  7. 响应日志

  8. 调用成功,接口调用次数 + 1

  9. 调用失败,返回一个规范的错误码

# 具体实现

# 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/**
1
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)

# 第六阶段

# 主要内容:

  1. 实现统一的接口鉴权和计费(RPC、Dubbo讲解)

# 网关业务逻辑

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

# 怎么调用其他项目的方法?

  1. 复制代码和依赖,环境
  2. HTTP请求(提供接口,供其他项目调用)
  3. RPC(Remote Procedure Call)远程过程调用
  4. 把公共的代码打个jar包,其他项目去引用

面试常问:HTTP 请求和 RPC 有什么区别

# HTTP 请求怎么调用?

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

# RPC

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

和直接 HTTP 调用的区别,RPC 优点:

  1. 对开发者更透明,减少很多的沟通成本
  2. RPC 向远程服务器发送请求时,未必使用 HTTP 协议,比如还可以使用 TCP/IP,性能更高。(内部服务更实适用)

RPC 调用模型:

image-20230514220826747

注意: 这里注册中心只提供信息,并不会帮助调用,实际调用还是提供者那边

# Dubbo 框架(RPC 实现)

其他 RPC 框架:GRPC、TRPC

最好的学习方式:阅读官方文档

https://dubbo.incubator.apache.org/zh/docs3-v2/java-sdk/quick-start/spring-boot/

# 两种使用方式

  1. Spring Boot代码(注解+编程式):写Java接口,服务提供者和消费者都去引用这个接口 偏程导
  2. DL(接口调用语言):创建一个公共的接口定义文件,服务提供者和消费者读取这个文件。优点是跨语言,所有的框架都认识

底层是Triple协议: https://dubbo.incubator.apache.org/zh/docs3-v2/java-sdk/concepts-and-architecture/triple/

# 官方的示例项目学习

zookeeper 注册中心:通过内嵌的方式运行,更方便

最先启动注册中心(EmbeddedZooKeeper,内嵌的注册中心),然后启动服务提供者(ProviderApplication),再启动服务消费者(ConsumerApplication)

# 整合运用

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

zooKeeper 会有版本问题,解决起来比较麻烦

建议用 Nacos!

整合 Nacos 注册中心:https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/registry/nacos/

注意:

  1. 服务接口类必须要在同一个包下,建议是抽象出一个公共项目(放接口、实体类等)
  2. 设置注解(比如启动类的 EnableDubbo、接口实现类和 Bean 引用的注解)
  3. 添加配置
  4. 服务调用项目和提供者项目尽量引入相同的依赖和配置

添加依赖

依赖从官方示例项目中复制粘贴过来的不行,要从 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>
1
2
3
4
5
6
7
8
9
10
11

# 第七阶段

# 主要内容:

  1. 开发抽象公共服务
  2. 实现网关核心业务流程
  3. 开发管理员接口分析功能
  4. 上线分析和扩展

# 梳理网关业务逻辑

以下操作可以复用:

  1. 去数据库中查是否已分配给用户秘钥(ak、sk 是否合法)
    • 先根据 ak 判断用户是否存在,查到 secretKey
    • 对比 sk 和用户传的加密后的 sk 是否一致
  2. 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)
  3. 调用成功,接口调用次数+ 1 invokeCount

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

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

# 抽象公共服务

项目名: cmapi-common 目的是让方法、实体类在多个项目间复用,减少重复编写

服务抽取:

  1. 数据库中查是否已分配给用户秘钥 (根据 accessKey 拿到用户信息,返回用户信息,为空表示不存在)
  2. 从数据库中查询模拟接口是否存在(请求路径、请求方法、请求参数,返回接口信息,为空表示不存在)
  3. 接口调用次数 + 1invokeCount (accessKey、secretKey (标识用户),请求接口路径

步骤:

  1. 新建干净的 maven 项目,只保留必要的公共依赖
  2. 抽取 service 和实体类
  3. install 本地 maven 包
  4. 让服务提供者引入 common 包,测试是否正常运行
  5. 让服务消费者引入 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 的页面

上次更新: 2025/4/3 17:16:48
功能涵盖
笔记

← 功能涵盖 笔记→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式