Spring Cloud Gateway
什么是API网关
API网关是随微服务概念兴起的一种架构模式,位于底层微服务与客户端的中间层,用于针对客户端的请求进行转发、安全认证、鉴权、监控、流控、负载均衡等通用功能。
概述
在微服务架构下,原所有功能都在单一代码库下,变为各个独立的微服务项目;随之带来的问题如:1.原有在单一代码库下做一次安全认证即可,现拆分成微服务后请求每个服务都需做一次安全验证,导致成本过高,每新增一个服务都需做一套重复的安全验证;2.拆分为微服务后,多个微服务客户端如何合理的调用?3.针对一些跨域请求,是否需每个服务都需额外处理呢?
针对以上难题,微服务引入了API网关的概念,API网关为微服务提供了统一的路由管理,作为系统的统一入口,为客户端或内部服务做中转,并能在网关层实现通用的业务逻辑、如安全认证、鉴权、路由转发、安全策略、接口防刷、监控日志等。

Spring Cloud Gateway是什么
Spring Cloud Gateway是基于Spring官方推出的第二代网关框架,定位取代Netflix zulu;Spring Cloud Gateway是基于Fliter的方式(责任链模式)进行提供网关基本功能;它是由WebFulx + Netty + Reactor实现的响应式(观察者模式)API网关,故此他不能在传统的servlet中工作,也不能构成war包。
Spring Cloud Gateway
核心概念
路由
路由是将请求映射到特定地址的功能,是网关最基础的部分,路由包含一个ID、目的的URL、一组断言工厂、一组Filter组成
过滤器
在Spring Cloud Gateway中Filter分为Gateway Filter和Global Filter,针对请求及响应的一些处理。
断言
断言是用于匹配请求的条件,它是路由规则的一部分,如果断言为真,则说明请求的URL和配置的路由匹配,可继续后续操作执行。
负载均衡
针对服务多个实例时,通过负载均衡算法,使流量均匀分布至每个服务。
工作原理

客户端发起请求,如请求和路由匹配,该请求会被发送到网关特定的Web处理程序,由特定的处理程序执行请求过滤链。
在过滤链中间虚线分割代表:会在发送后端服务前后进行执行不同的过滤器,具体区分为pre过滤器及post过滤器,pre过滤器一般用于在请求后端前的一些请求参数、请求头的一些校验;post过滤器是在请求后端服务响应后对响应结果的处理过滤器。
小试牛刀
引入依赖
<!-- 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>
<!-- 3.x 版本中去除了原有的 LoadBalancer 相关的代码和类,交由loadbalancer实现,变了成了可拔插的插件 故此需单独引入 -->
<!-- 负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
编写YAML文件
server:
port: 8888
spring:
application:
name: share-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.1.101:8848
namespace: zyl
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order-api/** # 断言,路径相匹配的进行路由
filters:
- StripPrefix=1
- id: user-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-user #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/user-api/** # 断言,路径相匹配的进行路由
filters:
- StripPrefix=1
路由断言工厂配置
路由断言,判断请求是否符合要求,符合则转发到路由目的地。application.yml配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。
路径匹配
spring:
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order-api/** # 断言,路径相匹配的进行路由
filters:
- StripPrefix=1
Header匹配
spring:
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order-api/** # 断言,路径相匹配的进行路由
- Header=X-Request-Id, \d+
filters:
- StripPrefix=1
过滤器工厂配置
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
添加请求头
spring:
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order-api/** # 断言,路径相匹配的进行路由
#配置过滤器工厂
filters:
- StripPrefix=1
- AddRequestHeader=X-Request-color, red #添加请求头
自定义过滤器工厂
spring:
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order-api/** # 断言,路径相匹配的进行路由
#配置过滤器工厂
filters:
- StripPrefix=1
- CheckAuth=auth, zyl
全局过滤器配置
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
GatewayFilter:网关过滤器,需要通过spring.cloud.routes.filters配置在具体的路由下,只作用在当前特定路由上,也可以通过配置spring.cloud.default-filters让它作用于全局路由上。
GlobalFilter:全局过滤器,不需要再配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter包装成GatewayFilterChain能够识别的过滤器。
LoadBalancerClientFilter
spring:
gateway:
#设置路由:路由id、路由到微服务的uri、断言
routes:
- id: order-api #路由ID,全局唯一,建议配置服务名
uri: lb://share-order #lb 整合负载均衡器ribbon,loadbalancer
predicates:
- Path=/order-api/** # 断言,路径相匹配的进行路由
#配置过滤器工厂
filters:
- StripPrefix=1
自定义全局过滤器
自定义全局过滤器定义方式是实现GlobalFilter接口。每一个过滤器都必须指定一个int类型的order 值,order值越小,过滤器优先级越高,执行顺序越靠前。GlobalFilter通过实现Ordered接口来指定order值
/**
* 每一个过滤器都必须指定一个int类型的order值,order值越小,过滤器优先级越高,执行顺序越靠前。
* GlobalFilter通过实现Ordered接口,来指定order值
*/
@Slf4j
@Component
public class CheckAuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//获取token
String token = exchange.getRequest().getHeaders().getFirst("token");
if (null == token) {
log.info("token is null");
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Content-Type",
"application/json;charset=UTF-8");
// 401 用户没有访问权限
response.setStatusCode(UNAUTHORIZED);
byte[] bytes = UNAUTHORIZED.getReasonPhrase().getBytes();
DataBuffer buffer = response.bufferFactory().wrap(bytes);
// 请求结束,不继续向下请求
return response.writeWith(Mono.just(buffer));
}
// TODO 校验token进行身份认证
log.info("校验token");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 2;
}
}
跨域配置
在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。
同源策略(Same Orgin Policy)是一种约定,它是浏览器核心也最基本的安全功能,它会阻止一个域的js脚 本和另外一个域的内容进行交互,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源 (即在同一个域)就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)。
YAML配置
spring:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTION
JAVA配置
@Configuration
public class CorsConfig {
@Bean
public 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);
}
}

浙公网安备 33010602011771号