Spring Cloud Gateway
官网:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
Spring Cloud中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,迟迟不发布版本,SpringCloud最后自己研发了一个网关替代Zuul,那就是Spring Cloud Gateway
Spring Cloud Gateway 是 Spring Cloud 的一个全新子项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor是一个运行在JVM上的反应式编程基础库 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。
spring Cloud Gateway 特性
- 基于Spring Framework 5,Project Reactor和Spring Boot 2.0构建
- 动态路由:能够匹配任何请求属性
- 可以对路由指定 Predicate(断言)和Filter(过滤器)
- 集成Spring Cloud 的服务发现功能
- 易于编写的Predicate(断言)和Filter(过滤器)
- 请求限流功能
- 支持路径重写
Spring Cloud Gateway的核心概念
- Route 路由,它是网关的基础元素,包含ID、目标URI、断言、过滤器组成,当前请求到达网关
时,会通过Gateway Handler Mapping,基于断言进行路由匹配,当断言为true时,匹配到路由
进行转发
- Predicate,断言,java8的一个函数,它可以允许开发人员去匹配HTTP请求中
的元素,一旦匹配为true,则表示匹配到合适的路由进行转发
- Filter,过滤器,可以在请求发出的前后进行一些业务上的处理,比如授权、限流等。
它的整体工作原理如下。
其中,predicate就是我们的匹配条件;而filter,就可以理解为一个无所不能的拦截器。有了这两个元
素,再加上目标uri,就可以实现一个具体的路由了。
客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发
送到网关 Web 处理程序,此时处理程序运行特定的请求过滤器链。
过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。 pre 前置过滤器逻辑先
执行,然后执行代理请求;代理请求完成后,执行 post 后置过滤器逻辑
流程图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
构建项目
Spring Cloud Gateway 网关路由配置方式:
-
在配置文件 yml 中配置
引入依赖包
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
Spring Cloud Gateway 是使用 netty+webflux 实现因此不需要再引入 web 模块。
我们先来测试一个最简单的请求转发。
server:
port: 8080
spring:
cloud:
gateway:
routes:
- predicates: #-横线表示数组可以配置多个
- Path=/gateway/** #匹配gateway的请求
filters:
- StripPrefix=1 #请求跳过gateway
uri: http://localhost:8081/
访问请求 http://localhost:8080/gateway/config
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
可以看到已经转发成功了
断言部分 可以查看spring官网
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-after-route-predicate-factory
1.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] 在这个时间之后匹配路由
2.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] 在这个时间之前匹配路由
3.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] 在这2个时间的过程进行匹配路由
4.The Cookie Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: config_route #-横线表示数组可以配置多个
predicates:
- Path=/gateway/** #匹配gateway的请求
filters:
- StripPrefix=1 #请求跳过gateway
uri: http://localhost:8081/
- id: cookie_route
predicates:
- Cookie=name,mic
uri: https://baidu.com 根据cookie匹配对应的路由信息 key value格式
5.The Header Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+ 根据http协议中携带的header信息进行路由
6.The Host Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org 根据host匹配对应的路由
7.The Method Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST 根据请求方式匹配路由
8.The Path Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment} 根据路径匹配对应的路由信息
9.The Query Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green 根据查询条件匹配对应的路由
10.The RemoteAddr Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24 根据ip地址匹配对应的路由
11.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
12.The XForwarded Remote Addr Route Predicate Factory
spring:
cloud:
gateway:
routes:
- id: xforwarded_remoteaddr_route
uri: https://example.org
predicates:
- XForwardedRemoteAddr=192.168.1.1/24
访问http://localhost:8080
请求中加一个cookie信息
可以看到下面的信息已经转发到一个html登录界面
下面来看看springCloud中cookie是怎么实现的
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.cloud.gateway.handler.predicate;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
import javax.validation.constraints.NotEmpty;
import org.springframework.http.HttpCookie;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
public class CookieRoutePredicateFactory extends AbstractRoutePredicateFactory<CookieRoutePredicateFactory.Config> {
public static final String NAME_KEY = "name";
public static final String REGEXP_KEY = "regexp";
public CookieRoutePredicateFactory() {
super(CookieRoutePredicateFactory.Config.class);
}
public List<String> shortcutFieldOrder() {
return Arrays.asList("name", "regexp"); //配置文件中的字段映射可配置多个
}
public Predicate<ServerWebExchange> apply(CookieRoutePredicateFactory.Config config) {
return new GatewayPredicate() { //Predicate java8中的一个函数接口中的test方法返回一个true/false的boolean
public boolean test(ServerWebExchange exchange) {
List<HttpCookie> cookies = (List)exchange.getRequest().getCookies().get(config.name); //获得配置文件中的参数
if (cookies == null) {
return false;
} else {
Iterator var3 = cookies.iterator();
HttpCookie cookie;
do {
if (!var3.hasNext()) {
return false;
}
cookie = (HttpCookie)var3.next();
} while(!cookie.getValue().matches(config.regexp));
return true;
}
}
public Object getConfig() {
return config;
}
public String toString() {
return String.format("Cookie: name=%s regexp=%s", config.name, config.regexp);
}
};
}
@Validated
public static class Config {
@NotEmpty
private String name;
@NotEmpty
private String regexp;//正则表达式匹配
public Config() {
}
public String getName() {
return this.name;
}
public CookieRoutePredicateFactory.Config setName(String name) {
this.name = name;
return this;
}
public String getRegexp() {
return this.regexp;
}
public CookieRoutePredicateFactory.Config setRegexp(String regexp) {
this.regexp = regexp;
return this;
}
}
}
- 自定义实现AuthRoutePredicateFactory
Auth的后缀必须是RoutePredicateFactory 这样 因为springcloudGateway 会进行筛选Predicate为Authn的key进行截取
如果实现自定义的实现必须按照这个格式来
package com.example.springcloudgateway8080;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
@Component
public class AuthRoutePredicateFactory extends AbstractRoutePredicateFactory<AuthRoutePredicateFactory.Config> {
public AuthRoutePredicateFactory() {
super(Config.class);
}
private static final String NAME_KEY="name";
private static final String VALUE_KEY="value";
@Override
public List<String> shortcutFieldOrder() {//快捷配置多个参数
return Arrays.asList(NAME_KEY,VALUE_KEY);//name和value就是配置文件中的参数
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
//Header中携带了某个值,进行header的判断
return (exchange->{
HttpHeaders headers=exchange.getRequest().getHeaders();
List<String> headerList=headers.get(config.getName());
return headerList.size()>0;
});
}
public static class Config {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
}
配置文件
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: config_route #-横线表示数组可以配置多个
predicates:
- Path=/gateway/** #匹配gateway的请求
filters:
- StripPrefix=1 #请求跳过gateway
uri: http://localhost:8081/
- id: cookie_route
predicates:
#- Cookie=name,mic
- Path=/define/**
- Auth=Authorization,token
uri: https://baidu.com
访问:http://localhost:8080/define
server:
port: 8080
spring:
cloud:
gateway:
routes:
- id: config_route #-横线表示数组可以配置多个
predicates:
- Path=/gateway/** #匹配gateway的请求
filters:
- StripPrefix=1 #请求跳过gateway
uri: http://localhost:8081/
- id: cookie_route
predicates:
#- Cookie=name,mic
- Path=/define/**
- Auth=Authorization,token
uri: https://www.baidu.com
访问:http://localhost:8080/define