文章目录
- 中文官网文档:
https://www.springcloud.cc/spring-cloud-greenwich.html#_spring_cloud_gateway
一、前奏
1.1、什么是服务网关
- PI Gateway(APIGW / API 网关),顾名思义,是出现在系统边界上的一个面向 API 的、串行集中式的强管控服务,这里的边界是企业 IT 系统的边界,可以理解为企业级应用防火墙,主要起到隔离外部访问与内部系统的作用。在微服务概念的流行之前,API 网关就已经诞生了,例如银行、证券等领域常见的前置机系统,它也是解决访问认证、报文转换、访问统计等问题的。
- API 网关的流行,源于近几年来移动应用与企业间互联需求的兴起。移动应用、企业互联,使得后台服务支持的对象,从以前单一的Web应用,扩展到多种使用场景,且每种使用场景对后台服务的要求都不尽相同。这不仅增加了后台服务的响应量,还增加了后台服务的复杂性。随着微服务架构概念的提出,API网关成为了微服务架构的一个标配组件。
- API 网关是一个服务器,是系统对外的唯一入口。API 网关封装了系统内部架构,为每个客户端提供定制的 API。所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有非业务功能。API 网关并不是微服务场景中必须的组件,如下图,不管有没有 API 网关,后端微服务都可以通过 API 很好地支持客户端的访问。
但对于服务数量众多、复杂度比较高、规模比较大的业务来说,引入 API 网关也有一系列的好处:
- 性能:API 高可用,负载均衡,容错机制。
- 安全:权限身份认证、脱敏,流量清洗,后端签名(保证全链路可信调用),黑名单(非法调用的限制)。
- 日志:日志记录,一旦涉及分布式,全链路跟踪必不可少。
- 缓存:数据缓存。
- 监控:记录请求响应数据,API 耗时分析,性能监控。
- 限流:流量控制,错峰流控,可以定义多种限流规则。
- 灰度:线上灰度部署,可以减小风险。
- 路由:动态路由规则。
- 黑名单等
1.2、什么是Gateway
- Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的 网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。
- 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 也非常方便
1.3、 Gateway和Zuul的性能比较
-
Spring Cloud Gateway基于Spring 5、Project Reactor、Spring Boot 2,使用非阻塞式的API,内置限流过滤器,支持长连接(比如 websockets),在高并发和后端服务响应慢的场景下比Zuul1的表现要好。
-
Zuul基于Servlet2.x构建,使用阻塞的API,没有内置限流过滤器,不支持长连接。
1.4、Nginx与网关的区别
1.4.1、相同点
都是可以实现对api接口的拦截,负载均衡、反向代理、请求过滤等,可以实现和网关一样的效果;
1.4.2、不同点
-
Nginx采用C语言编写的,在微服务领域中,都是自己语言编写的,比如我们使用java构建微服务项目,Gateway就是java语言编写的。毕竟Gateway属于Java语言编写的, 能够更好对微服务实现扩展功能,相比Nginx如果想实现扩展功能需要结合Nginx+Lua语言等。
-
Nginx属于服务器端负载均衡器,而Gateway采用本地负载均衡器
的形式。
二、使用
2.1依赖、yml配置
2.1.1、 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
注意: 如果引入了Gateway的依赖,就不能引入 spring-boot-starter-web
的依赖,否则会报错!!!
2.1.2、 yml配置
name: gateway_test cloud: gateway: routes: - ##路由Id,唯一 - id: test1 ##转发的uri uri: http://localhost:8081 ##断言 predicates: #path的路径会加到uri后边,比如访问http:/test1/getXXX,那么路由转发的地址就为http://localhost:8081/test1/getXXX - Path=/test1/ **(注意**前边没有空格,因为连着在markdown做笔记的样式有问题,所以加了一个) - id: test2 ## uri以lb://开头(lb代表从注册中心获取服务),后面接的就是你需要转发到的服务名称 uri: lb://test2 predicates: #path的路径会加到uri后边, - Path=/test2/**`
2.2 断言
断言的类型如下(具体使用看文档,最上边):
2.3 过滤器
Spring Cloud Gateway 根据作用范围划分为 GatewayFilter
和 GlobalFilter
,二者区别如下:
GatewayFilter
:网关过滤器,需要通过 spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过 spring.cloud.default-filters 配置在全局,作用在所有路由上。
GlobalFilter
:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter 包装成 GatewayFilterChain 可识别的过滤器,它为请求业务以及路由的 URI 转换为真实业务服务请求地址的核心过滤器,不需要配置系统初始化时加载,并作用在每个路由上。
2.3.1 全局过滤局使用
/**
* @author ly
*/
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
private static final int order=1;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("in MyGlobalFilter..");
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
MultiValueMap<String, String> params = request.getQueryParams();
List<String> nameList = params.get("token");
if (nameList != null) {
/*
.....一系列验证代码
*/
//chain.filter(exchange);表示放行,这里
return chain.filter(exchange);
}
//返回前端消息(不放行)
DataBuffer buffer = response.bufferFactory().wrap("亲,没有token数据哟".getBytes());
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
/**
* 指定顺序
*
*/
@Override
public int getOrder() {
return order;
}
}
2.3.2 GatewayFilter
- 网关过滤器用于拦截并链式处理 Web 请求,可以实现横切与应用无关的需求,比如:安全、访问超时的设置等。修改传入的 HTTP 请求或传出 HTTP 响应。Spring Cloud Gateway 包含许多内置的网关过滤器工厂一共有 22 个,包括头部过滤器、 路径类过滤器、Hystrix 过滤器和重写请求 URL 的过滤器, 还有参数和状态码等其他类型的过滤器。根据过滤器工厂的用途来划分,可以分为以下几种:Header、Parameter、Path、Body、Status、Session、Redirect、Retry、RateLimiter 和 Hystrix。
具体的使用看官方文档(最上边)
(1) 定义filter
实现GatewayFilter
接口,代码如下
/**
* @author ly
*/
public class MyGateFilter implements GatewayFilter, Ordered {
private static final int ORDER = -1;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("in MyGateFilter..");
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
HttpMethod method = request.getMethod();
if (!HttpMethod.POST.equals(method.name())) {
DataBuffer buffer = response.bufferFactory().wrap("请用post方法调用接口".getBytes());
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//指定编码,否则在浏览器中会中文乱码
response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
return response.writeWith(Mono.just(buffer));
}
//放行
return chain.filter(exchange);
}
@Override
public int getOrder() {
return ORDER;
}
}
(2)配置路由
/**
* @author ly
*/
@Configuration
public class RouteLocatorConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
return routeLocatorBuilder.routes().route(r ->
r.path("/test2/**")
.uri("lb://test2")
.id("test2")
.filter(new MyGateFilter()))
.build();
}
}