> 文章列表 > SpringCloud之Gateway组件简介

SpringCloud之Gateway组件简介

SpringCloud之Gateway组件简介

网关的理解

网关类似于海关或者大门出入都需要经过这个网关。别人不经过这个网关,永远也看不到里面的东西。可以在网关进行条件过滤,比如大门只有对应的钥匙才能入内。网关和大门一样,永远暴露在最外面

不使用网关

  • 前端需要记住每一个服务的IP和port

  • 如果有一个服务部署多台,那么前端需要自行分配

使用网关

  • 前端不需要记每一个服务的IP和port,只需要将请求发送到网关即可,网关根据资源路径做路由跳转

  • 网关中可以做安全控制 比如Token校验、限流等

  • 可以做负载均衡

Gateway的理解

是Spring官网推出的一套网关组件,用来取代Zuul

它的目的是为了让路由跳转更加方便、灵活,还提供了一些强大的过滤器功能。比如:IP黑名单、Token校验等

基于webFlux框架实现,webFlux框架底层使用了高性能的Reactor模式通信框架的Netty

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和Project Reactor等技术。

Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。

① Gateway工作原理

客户端发送请求到Gatewaty,然后Gateway HandlerMapping通过对比映射,找到与其匹配的路由,将其发送到Gateway WebHandler。Handler再通过指定的过滤器将请求分发到实际的业务逻辑,并返回。

在过滤器中可以做增加代码:

  • 请求之前[pre]做校验等

  • 请求之后[post]做日志输出等

Gateway核心逻辑:根据资源路径做路由转发,并且执行过滤器链。

② Gateway三大核心概念

路由(Route)

和eureka结合做动态路由

组成部分:一个路由ID、一个唯一资源定位符URI、一组断言、一组Filter

如果路由断言为真,那么URL和配置路由匹配

断言(Predicate)

返回一个boolean表达式

过滤器(Filter)

Gateway中的过滤器分为Gateway Filter(针对一个路由)和Global Filter(全局)

在过滤器中可以编写校验规则以及响应的处理

③ Gateway和Nginx区别

Nginx做限流、负载均衡、路由都需要修改nginx.conf配置文件

Gateway和eureka结合,实现了自动路由跳转;和Ribbon集合,实现了负载均衡。Gateway也能够通过配置进行限流的实现

 

 

路由使用

① 访问流程

② Loing-service

@RestController
public class LoginController {@GetMapping("doLogin")public String doLogin(String username,String password){System.out.println(username+" -> "+password);String token = UUID.randomUUID().toString();return token;}
}

② Gateway-server

gateway依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

配置路由

server:port: 80
spring:application:name: gateway-servercloud:gateway:enabled: true # 默认开启Gatewayroutes: # 路由组- id: login-service-route # 路由ID 保证唯一uri: http://localhost:8080 # uri唯一资源定位符 url唯一资源标识符predicates: # 断言- Path=/doLogin # 和服务中的路径匹配

④ 编程式路由

不借助配置文件,使用编码的方式来实现路由转发

@Configuration
public class RouteConfig {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("anime-id", r->r.path("/anime").uri("https://www.bilibili.com")).route("variety-id",r->r.path("/variety").uri("https://www.bilibili.com")).build();}
}

如果在uri后面的资源路径和path中的路由一样,那么gateway不会把path中的路由拼接到uri后面。

编程式和配置文件的方式可以结合使用

动态路由

如果在路由转发时直接将URL写死,从而IP和port也被写死,那么Gateway将无法达到负载均衡的效果。应该是只提供服务名,然后通过这个名字去找对应的服务,从而达到负载均衡的效果

让Gateway服务也注册到注册中心中,那么Gateway就能够拥有所有的服务信息

Gateway会根据注册中心中的服务列表,以每个服务名为路径创建动态路由进行转发

① 第一种实现方式

使用lb(Load Balance)协议,表示启用Gateway的负载均衡功能

server:port: 80
spring:application:name: gateway-servercloud:gateway:enabled: true # 默认开启Gatewayroutes: # 路由组- id: login-service-route # 路由ID 保证唯一# uri: http://localhost:8080 # uri唯一资源定位符 url唯一资源标识符uri: lb://login-service # lb://服务名predicates:- Path=/doLogin # 和服务中的路径匹配

 调用:http://localhost/doLogin

② 第二种实现方式

使用服务发现,自动创建动态路由从而实现负载均衡

server:port: 80
spring:application:name: gateway-servercloud:gateway:enabled: true # 默认开启Gatewaydiscovery:locator:enabled: true # 开启动态路由lower-case-service-id: true # 将注册列表中的服务名小写

断言

在项目启动的时候,Gateway会去加载一些路由断言工厂,例如:After、Query

断言就是给路由增加一些匹配规则,如果发送的请求符合这些规则,就能够去访问,否则404。简单说这些匹配规则也就是一些boolean表达式,要么true进入,要么false拒绝

① 分类

 

② 使用

在配置文件中,对某个路由进行操作。动态路由不能使用断言

spring:application:name: gateway-servercloud:gateway:enabled: true # 默认开启Gatewayroutes:- id: login-service-routeuri: lb://login-servicepredicates:- Path=/doLogin- Method=GET,POST # GET,POST请求能够访问- After=2022-11-02T17:23:16.423+08:00[Asia/Shanghai] # 在指定时间后才能访问 通过ZonedDateTime获取- Query=username,admin. # 必须给username传值 后面的值必须是:adminx

过滤器

Gateway中的过滤器和Servlet里面的过滤器差不多,用户修改进入HTTP请求和HTTP响应

分为GatewayFilter(针对某一个路由)和GlobalFilter(全局过滤)

① 自定义全局过滤器

在自定义过滤器中编写业务逻辑,比如Token校验、限流。

@Component
public class TestFilter implements GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 获取请求对象ServerHttpRequest request = exchange.getRequest();RequestPath path = request.getPath();// 打印路由以及服务名System.out.println(path);HttpHeaders headers = request.getHeaders();// 获取主机IPString ip = headers.getHost().getHostName();System.out.println(ip);// 获取响应对象ServerHttpResponse response = exchange.getResponse();// 放过return chain.filter(exchange);}
}

 定义过滤器顺序

@Component
public class TestFilter implements Ordered {@Overridepublic int getOrder() {// 数字越小 越往前return 0;}
}

返回值处理

// 获取响应对象
ServerHttpResponse response = exchange.getResponse();
// 设置响应头
response.getHeaders().set("content-Type","application/json;charset=UTF-8");
// 封装返回数据
Map<String,Object> map = new HashMap<>();
map.put("code", 401);
map.put("msg","没有该权限");
ObjectMapper objectMapper = new ObjectMapper();
try {// 将map集合转为byte数组byte[] bytes = objectMapper.writeValueAsBytes(map);// 将byte数组包装成一个数据缓冲包DataBuffer wrap = response.bufferFactory().wrap(bytes);// 返回return response.writeWith(Mono.just(wrap));
} catch (JsonProcessingException e) {e.printStackTrace();
}

限流

在一定的时间段内,限制用户的访问频率。

① 限流模型

漏斗算法、令牌通算法、计算器算法、窗口滑动算法

入不敷出:生产令牌的速度赶不上使用的速度

  1. 系统以提前配置好的速率去生产令牌。

  2. 给令牌桶设置一个阈值,当桶满后,多余的令牌直接丢弃

  3. 客户发送请求都需要去拿令牌

  4. 如果没有拿到令牌该请求不能成功访问

  5. 如果拿到令牌将去访问服务,完成业务处理后删除令牌

  6. 当桶中的令牌数达到最低额度时,使用完的令牌返回

② Gateway中的限流

Gateway中已经内置了RequestRateLimiterGatewayFilterFactory,结合Redis做令牌桶算法。需要导入redis依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

 配置限流规则

@Configuration
public class RequestLimiterConfig {/*基于IP做限流*/@Bean@Primary // 主候选public KeyResolver ipKeyResolver(){return exchange-> Mono.just(exchange.getRequest().getHeaders().getHost().getHostName());}/*基于API接口最限流*/@Beanpublic KeyResolver apiKeyResolver(){return exchange -> Mono.just(exchange.getRequest().getPath().toString());}
}

修改配置文件

spring:application:name: gateway-servercloud:gateway:enabled: true # 默认开启Gatewayroutes:- id: login-service-routeuri: lb://login-servicepredicates:- Path=/doLoginfilters:- name: RequestRateLimiter # 过滤器名称args:key-resolver: '#{@ipKeyResolver}' # Bean对象的名字redis-rate-limiter.replenishRate: 1 # 每秒钟生产多少令牌redis-rate-limiter.burstCapacity: 3 # 令牌桶中的容量

只针对某一个路由

跨域配置

跨域:CORS同源策略。

因为网关是服务的最边缘,所有的请求都需要走网关,将跨域的配置写在网关。

编程式

@Configuration
public class CorsConfig {@Beanpublic CorsWebFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedMethod("*");config.addAllowedOrigin("*");config.addAllowedHeader("*");UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());source.registerCorsConfiguration("/", config);return new CorsWebFilter(source);}
}

配置文件

spring:cloud:gateway:globalcors:cors-configurations:'[/]': # 针对那些路径allowCredentials: true # 可以携带CookieallowedHeaders: '*'allowedMethods: '*'allowedOrigins: '*'

面试题相关

什么是微服务网关

Spring Cloud Gateway 是 Spring 官方基于 Spring 5.x,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全性、监视/指标和弹性。

 

使用Gateway的优势

Spring Cloud Gateway 可以看做是一个 Zuul 1.x 的升级版和代替品,比 Zuul 2 更早的使用 Netty 实现异步 IO,从而实现了一个简单、比 Zuul 1.x 更高效的、与 Spring Cloud 紧密配合的 API 网关。
Spring Cloud Gateway 里明确的区分了 Router 和 Filter,并且一个很大的特点是内置了非常多的开箱即用功能,并且都可以通过 SpringBoot 配置或者手工编码链式调用来使用
比如内置了 10 种 Router,使得我们可以直接配置一下就可以随心所欲的根据 Header、或者 Path、或者 Host、或者 Query 来做路由。
比如区分了一般的 Filter 和全局 Filter,内置了 20 种 Filter 和 9 种全局 Filter,也都可以直接用。当然自定义 Filter 也非常方便。

zuul和spring cloud gateway的对比

  • zuul:是Netflix的,是基于servlet实现的,阻塞式的api,不支持长连接。
  • gateway:是springcloud自己研制的微服务网关,是基于Spring5构建,能够实现响应式非阻塞式的Api,支持长连接

gateway的组成

  • 路由 : 网关的基本模块,有ID,目标URI,一组断言和一组过滤器组成
  • 断言:就是访问该旅游的访问规则,可以用来匹配来自http请求的任何内容,例如headers或者参数
  • 过滤器:这个就是我们平时说的过滤器,用来过滤一些请求的,gateway有自己默认的过滤器,具体请参考官网,我们也可以自定义过滤器,但是要实现两个接口,ordered和globalfilter