Spring Cloud微服务之Gateway
Spring Cloud Gateway
技术介绍
Spring Cloud Gateway是Spring公司基于Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。gateway用于替代zuul网关,有效提高网关服务性能。gateway不仅提供了统一的路由方式,并且还支持通过filter的形式提供网关的基本功能。
Spring Cloud Gateway 是 Spring Cloud 家族中的新一代微服务网关框架,它为构建 API 网关提供了强大的功能。Spring Cloud Gateway 使用的 WebFlux 中的 Reactor-Netty 响应式编程软件,底层使用了异步非阻塞的 Netty 通讯框架,性能更高,适合高并发业务场景。
官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
核心模块
- 路由:Route定义了一个路由的基本信息,是网关的基本单元,包含 ID、目标 URI、断言集合、过滤器集合。通过路由,Gateway可以将请求转发到后端的某个具体服务上。
- 断言:Predicate是一个Java 8的Predicate,它可以根据请求的各种属性(例如请求的路径、方法、Header等)来匹配请求,如果匹配成功,则将请求交给对应的Route处理。
- 过滤器:在请求被路由前后修改请求和响应的机制。是网关的核心工作单元。
工作流程
- 客户端发送请求到Gateway。
- Gateway根据定义的Route和Predicate来匹配请求。
- 如果请求匹配成功,Gateway将请求交给对应的Filter链进行处理。
- Filter链依次处理请求,可以在此时进行请求的修改、鉴权、限流等操作。
- Filter链处理完毕后,将请求转发给后端服务。
- 后端服务处理请求并返回响应。
- 响应经过Filter链处理后返回给客户端。
主要功能
路由转发(动态路由):根据请求的路径或其他属性,网关可以将请求路由到相应的后端服务,使得微服务能够按照特定规则进行组织和访问。
负载均衡:网关可以将请求分发到多个服务实例中,以提高系统的性能和可用性,并避免单个服务实例的过载。
限流熔断(流控):网关可以实施限流策略,限制对后端服务的请求流量,防止系统被过度请求而导致的性能下降或宕机。
跨域配置:打通前后端,支持前端的跨域请求。
认证鉴权:网关可以验证请求的身份并进行授权,确保只有经过身份验证的用户才能访问服务,从而保护系统的安全性。
反向代理:代理后端服务器,隐藏微服务地址,对系统起到保护作用。

核心特性
gateway网关搭建
<dependencies>
<!--引入gateway网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--引入nacos的服务发现,将网关注册到配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--引入nacos负载均衡的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
配置断言
gateway自带的路由断言

配置使用
简单写法
spring:
cloud:
gateway:
routes:
- id: user-service # 服务的名字
uri: lb://user-service # 负载均衡访问服务的地址
predicates: # 断言
- Path=/api/user/** # 服务的映射路径
全写法
spring:
cloud:
gateway:
routes:
- id: user-service # 服务的名字
uri: lb://user-service # 负载均衡访问服务的地址
predicates: # 断言
- name: Path # 断言规则的名字
args:
patterns: /api/user/** # 路径规则
matchTrailingSlash: false # 路径中或末尾,加/和不加/是两种路径(默认为true)
自定义断言工厂
需求:满足以下定义的断言规则,由于vip规则不存在,所以需要我们自行创建断言规则
spring:
cloud:
gateway:
routes:
- id: bing
uri: https://cn.bing.com
predicates:
- Path=/search
- Query=q,haha
- Vip=user,nf
@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {
//需要有一个无参构造器
public VipRoutePredicateFactory() {
super(VipRoutePredicateFactory.Config.class);
}
//提供一个短写法的顺序方法
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("param","value");
}
//之后需要实现断言的逻辑规则
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
//需要new一个网关的断言类
@Override
public boolean test(ServerWebExchange serverWebExchange) {
//这个对象里边封装了所有的请求和响应对象
ServerHttpRequest request = serverWebExchange.getRequest(); //拿到请求
String first = request.getQueryParams().getFirst(config.param); //获取请求参数为config.param值的请求参数
return StringUtils.hasText(first) && first.equals(config.value); //判断值是否为空,且是否与config.value的值相等
}
};
}
/**
* 可以配置的参数
*/
@Validated
public static class Config {
//需要一个内部类
private @NotEmpty String param;
private @NotEmpty String value;
//编写这两个值的get和set方法
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
配置路由
路由信息由id、uri、断言集合和过滤器集合这4部分组成,配置形式如下:
路由id:路由的唯一标示
路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
路由断言(predicates):判断路由的规则,
路由过滤器(filters):对请求或响应做处理
spring:
cloud:
gateway:
routes:
- id: service-order # 服务的名字
uri: lb://service-order # 负载均衡访问服务的地址 lb表示负载均衡协议 // 后面跟服务名
predicates: # 断言
- Path=/api/order/** # 服务的映射路径
- id: service-product
uri: lb://service-product
predicates:
- Path=/api/product/**
order: 0 # 路由顺序:数值越小,优先等级越高
# filters: # 配置过滤器
配置过滤器
网关过滤器基于配置和代码实现,可分为两种:
GatewayFilter:Gateway网关过滤器,是针对单个路由的过滤器,又称局部过滤器(路由过滤器),其功能是针对访问的URL起到一定的过滤效果。通过配置实现。
GlobalFilter:从名称而言,那就是全局过滤器,对所有的路由都有效。
- 自定义全局过滤器:是需要实现具体的Java类来实现GlobalFilter接口,这其中可以根据进行权限的验证,HTTP请求的头部添加等等。
- 内置全局过滤器:Spring Cloud Gateway 自带的 30+ 过滤器,也是通过配置显示。也称为默认过滤器
网关过滤器 = 局部过滤器 = 路由过滤器
内置全局过滤器 = 默认过滤器
过滤器工厂
gateway提供的过滤器工厂有31种,下面介绍常用的几种
| 名称 | 说明 |
|---|---|
| AddRequestHeader | 给当前请求添加一个请求头 |
| RemoveRequestHeader | 移除请求中的一个请求头 |
| AddResponseHeader | 给响应结果中添加一个响应头 |
| RemoveResponseHeader | 从响应结果中移除有一个响应头 |
| RequestRateLimiter | 限制请求的流量 |
过滤器的使用
作为局部过滤器
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Truth, Itcast is freaking awesome! # 添加请求头
作为内置全局过滤器
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Truth, Itcast is freaking awesome!
自定义全局过滤器
实现GlobalFilter和Ordered接口,可以配置一下过滤器的执行顺序
- 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
- GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
- 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增。
- 当过滤器的order值一样时,会按照内置全局过滤器>局部过滤器>自定义全局过滤器
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Order(-1)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// 2.获取authorization参数
String auth = params.getFirst("authorization");
// 3.校验
if ("admin".equals(auth)) {
// 放行
return chain.filter(exchange);
}
// 4.拦截
// 4.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 4.2.结束处理
return exchange.getResponse().setComplete();
}
}
跨域支持
跨域:域名、端口、协议不一致就是跨域
跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
解决方式
spring:
cloud:
gateway:
# 。。。
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期

浙公网安备 33010602011771号