大部分资料都来自Gateway官网 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到api,并为它们提供跨领域的关注点,例如:熔断、限流、重试等。
Spring Cloud Gateway建立在Spring Framework5、Project Reactor和SpringBoot2之上,使用非阻塞API
客户端向SpringCloudGateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。此处理程序通过特定于请求的筛选器链运行请求。过滤器被虚线分隔的原因是过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“预”过滤逻辑。然后发出代理请求。发出代理请求后,运行“post”过滤器逻辑。
Route(路由)
路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
Predicate(断言)
参考的是java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤)
指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
新建module 命名gateway
pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-eureka</artifactId>
<groupId>com.cto</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway</artifactId>
<packaging>jar</packaging>
<dependencies>
<!--EurekaClient-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<!--
SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml
server:
port: 8888
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由功能
routes:
- id: cloud-provider
uri: lb://cloud-provider #服务的application.name
predicates:
- Path=/**
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7000/eureka/
instance:
hostname: cloud-gateway-service
#日志
logging:
level:
com:
cto:
cloud: debug
org:
springframework:
web: info
file: log/cloud-gateway.log
启动类
package com.cto.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
*
* @author Zhang Wei
* @date 2020/5/24 01:33
* @version v1.0.1
*/
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
依次启动 注册中心7000、gateway8888、生产者9001、生产者9002
访问:http://localhost:8888/provider/getData
可以看到路由动态代理成功,会轮循访问两个生产者
常用的Route Predicate
1.After Route Predicate
2.Before Route Predicate
3.Between Route Predicate
4.Cookie Route Predicate
5.Header Route Predicate
6.Host Route Predicate
7.Method Route Predicate
8.Path Route Predicate
9.Query Route Predicate
参与官网 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories
以After Route Predicate为例
意思就是设置一个时间,到某个时间以后才可以通过网关访问,代码如下
spring:
cloud:
gateway:
routes:
- id: cloud-provider
uri: lb://cloud-provider
predicates:
- After=2020-05-24T02:14:46.014+08:00[Asia/Shanghai]
时间获取方式如下:
import java.time.ZonedDateTime;
/**
*
* @author Zhang Wei
* @date 2020/5/24 02:13
* @version v1.0.1
*/
public class Test {
public static void main(String[] args) {
ZonedDateTime zt = ZonedDateTime.now();
System.out.println(zt);
}
}
其他剩下的几种,可参与官网进行尝试,都有demo
Filter的生命周期
pre(业务逻辑之前) post(业务逻辑之后)
Filter的种类
默认的Filter介绍请参与官网文档,根据介绍直接在yml配置即可
单一Filter https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories
全局Filter https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#global-filters
实现 GlobalFilter ,Ordered
在gateway添加config包,添加配置类
模拟拦截用户是否带了token
package com.cto.cloud.filter;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.result.view.RequestContext;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
*
* @author Zhang Wei
* @date 2020/5/19 23:52
* @version v1.0.1
*/
@Component
public class GlobalTokenFilter implements GlobalFilter, Ordered {
/**
* 数字越小 优先级越高
* @return
*/
@Override
public int getOrder() {
return 1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//判断第一个参数是不是name,如果是继续,不是则返回自定义错误 Token验证也是一个道理,从header中获取
String name = exchange.getRequest().getQueryParams().getFirst("name");
if(StringUtils.isEmpty(name)){
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
byte[] bytes = "{\"status\":\"-1\",\"msg\":\"error\"}".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
return exchange.getResponse().writeWith(Flux.just(buffer));
}
return chain.filter(exchange);
}
}
监听没个接口请求的信息
package com.cto.cloud.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
*
* @author Zhang Wei
* @date 2020/5/19 23:52
* @version v1.0.1
*/
@Component
public class GlobalRunTimeFilter implements GlobalFilter, Ordered {
private static final String ELAPSED_TIME_BEGIN = "elapsedTimeBegin";
/**
* 数字越小 优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
exchange.getAttributes().put(ELAPSED_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
Long startTime = exchange.getAttribute(ELAPSED_TIME_BEGIN);
if (startTime != null) {
System.out.println(exchange.getRequest().getURI().getRawPath() + ": " + (System.currentTimeMillis() - startTime) + "ms");
System.out.println(exchange.getRequest().getQueryParams());
}
})
);
}
}
重启gateway8888 访问:http://localhost:8888/provider/getData
没带参数,gateway直接拦截并没有访问9001或者9002,可自行查看日志
当带了约定的参数,成功访问
查看网关后台日志,请求时间Filter也生效
Github地址
陆续更新中……