springcloud---gateway

gateway是springcloud推出的第二代网关,取代了之前的zuul。

第一个简单的gateway

创建一个springboot项目,引入gateway的依赖

<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

首先需要在改springbot项目中注入一个RouteLocator类型的bean

@SpringBootApplication
@RestController
public class Gatewayservice7106Application {

	public static void main(String[] args) {
		SpringApplication.run(Gatewayservice7106Application.class, args);
	}

	@Bean
	public RouteLocator myRoute(RouteLocatorBuilder builder) {
		return builder.routes().route(p ->
                p.path("/get")
                .filters(f -> f.setRequestHeader("token", "qwer"))
                .uri("http://httpbin.org:80")
        ).route(p ->
        p.path("/posts")
        .filters(f -> f.hystrix(config
                -> config.setName("cmd").setFallbackUri("forward:/fallback")))
        .uri("http://httpbin.org:80")).build();

	}

	@GetMapping("/fallback")
	public String fallBack() {
	    return "dead";
    }

}

这里通过RouteLocatorBuilder来创建路由。由route()方法来路由请求,该方法返回一个RouteLocatorBuilder类里面的Router类,可链式写。
该route方法里面依次定义了匹配的请求路径,需要执行的过滤器,最后需要转发的地址。第二个过滤器中使用了Hystrix。

predicate

springcloud里面的predicate用于请求和路由进行匹配。
datetime:时间校验
AfterRoutePredicateFactory:请求时间满足在配置时间之后
BeforeRoutePredictateFactory:请求时间满足在配置时间之前
BetweenRoutePredicateFactory:请求时间满足配置时间时间
Cookie:cookie校验
CookieRoutePredicateFactory:指定Cookie正则匹配
Header:请求头校验
HeaderRoutePredicateFactory:请求指定Header正则匹配指定的值
CloudFoundryRouteServiceRoutePredicateFactory:请求Header是否包含指定名称
Host校验:
HostRoutePredicateFactory:请求Host匹配指定的值
Method校验:
MethodRoutePredicateFactory:请求的method匹配配置的方法名
Path校验:
PathRoutePredicateFactory:请求路径正则匹配
Queryparam校验:
QueryRoutePredicateFactory:请求参数正则匹配指定的值
RemoteAddr 请求远程地址校验:
RemoteAddrRoutePredicateFactory:请求远程地址匹配指定的值

每一种predicate都会对当前的客户端请求进行判断,是否满足当前的要求,如果满足则交给当前请求处理。如果有很多个Predicate,并且一个请求满足多个Predicate,则按照配置的顺序第一个生效。
下面操作一下这些predicate,还是用上面的gateway工程:
在application.yml文件中配置如下

server:
  port: 7106
spring:
  profiles:
    active: after_route
---
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: http://httpbin.org:80/get
        predicates:
        - After=2019-01-20T10:15:47.789+08:00
  prefiles: after_route

AfterRoutePredicateFactory

其中,spring.profiles.active:after_route表示启动文件还有一个,名为after_route。“—”表示新建一个yml文件,用profiles指定这个文件名。routes:之后的就是路由配置,id必须要有的,每个route都需要一个唯一的id,uri指路由转发的地址,predicates是配置上面的那些predicate类型。-after指定的就是AfterRoutePredicateFactory,其时间格式为:年-月-日T时-分-秒.毫秒+时区。
这里配置的时间为1月20号,请求应该是会转发到http://httpbin.org:80/get去的。
访问一下,发现确实转发到该地址了
在这里插入图片描述
如果把时间配置在当前时间之后,再次请求就会404。

BeforeRoutePredictateFactory

和AfterRoutePredicateFactory相反。
把上面的application.yml文件中配置修改一下,使用BeforeRoutePredictateFactory

predicates:
#        - After=2019-01-20T10:15:47.789+08:00
        - Before=2019-08-20T10:15:47.789+08:00

请求一下http://localhost:7106/,就会转发到http://httpbin.org:80/get。
如果把时间改为1月份,再次访问就404了
如下
在这里插入图片描述

BetweenRoutePredicateFactory

这个就是配置一个时间段了。和上面两个功能一样
把predicates配置修改为如下

predicates:
        - Between=2019-01-20T10:15:47.789+08:00,2019-02-20T10:15:47.789+08:00

请求就404了。

CookieRoutePredicateFactory

这个就是校验请求中是否含有设置的cookie。
把配置文件中predicates的设置为如下,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Cookie=name,zgq
请求的cookie值随便改一个,就404了

在这里插入图片描述

HeaderRoutePredicateFactory

匹配请求头中是否包含设置的请求头,并且值是否匹配
把配置文件中predicates的设置为如下,请求头设置一个X-name=12,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Header=X-name,\d+ #请求头中是否包含X-name的请求头,并且值为数值
X-name值改为字符串,就404了

CloudFoundryRouteServiceRoutePredicateFactory

匹配请求head是否包含指定值

HostRoutePredicateFactory

匹配请求头中host是否满足条件
把配置文件中predicates的设置为如下,请求头设置一个Host=y.yuchai.com,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Host=y.yuchai.com
Host值改与一下,就404了

MethodRoutePredicateFactory

匹配请求类型
把配置文件中predicates的设置为如下,get方式请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Method=Get
请求方式改为post,就404了

QueryRoutePredicateFactory

匹配请求中的参数
把配置文件中predicates的设置为如下,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Query=name,zgq #请求参数中有name=zgq则匹配
参数值或名改一下,就404了

PathRoutePredicateFactory

匹配请求路径是否符合配置的规则
把配置文件中predicates的设置为如下,请求一下,就转发到http://httpbin.org:80/getl了
predicates:
- Path=/getName #请求路径中有/getName则匹配
路径改一下,就404了

gateway的路由过滤

gateway filter按照作用时间分为pre和post类型的过滤器。pre类型的过滤器为gateway转发请求之前起作用,post类型的过滤器为gateway收到业务服务响应之后,返回响应给客户端之前这段时间内起作用。
按照作用范围,又分为全局过滤器和单个路由的过滤器。
gateway提供的默认单个路由的过滤器有19个。
试下AddRequestHeader的过滤器,和Predicate配置一样,在yml中配置即可,如下

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: http://httpbin.org:80/get
        filters:
        - AddRequestHeader=X-name,zgq
        predicates:
        - After=2019-01-20T10:15:47.789+08:00

这样,在请求到达gateway之后,会加上一个请求头,再转发给http://httpbin.org:80/get。
其他我没找到,等我以后再来补充 =_= !

自定义过滤器

自定义单个路由的过滤器

需要创建类实现GatewayFilter接口和Orders接口

public class MyFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        exchange.getAttributes().put("requestTimeBegin", System.currentTimeMillis());
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    Long startTime = exchange.getAttribute("requestTimeBegin");
                    if (startTime !=null) {
                        System.out.println("请求耗时"+ (System.currentTimeMillis() - startTime));
                    }
                })
        );
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

然后注册该过滤器到route中

    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
	    return builder.routes().route(
	            r -> r.path("/*")
                .filters(f -> f.filter(new MyFilter())
                        .addRequestHeader("X-name", "zgq123"))
                        .uri("http://httpbin.org:80/get")
                .order(0)
                .id("my_filer")
        ).build();
    }

然后访问一下,请求头中加入了一个“x-name”的请求头

自定义过滤器工厂

public class MyFilterFactory extends AbstractGatewayFilterFactory<MyFilterFactory.Config> {

    public MyFilterFactory() {
        super(Config.class);
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("withParam");
    }

    @Override
    public GatewayFilter apply(MyFilterFactory.Config config) {
        return (exchange, chain) -> {
            exchange.getAttributes().put("startTime", System.currentTimeMillis());
            return chain.filter(exchange).then(
                    Mono.fromRunnable(() -> {
                        Long startTime = exchange.getAttribute("startTime");
                        if (startTime != null) {
                            System.out.println("耗时" + (System.currentTimeMillis() - startTime));
                        }
                    })
            );
        };
    }

    public static class Config {
        private boolean withParam;

        public boolean isWithParam() {
            return withParam;
        }

        public void setWithParam(boolean withParam) {
            this.withParam = withParam;
        }
    }
}

注册该Factory到IOC中

@Bean
    public MyFilterFactory registryMyFilterFactory() {
	    return  new MyFilterFactory();
    }

最后可以在yml文件中配置该过滤器工厂了

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: http://httpbin.org:80/get
        filters:
        - MyFilterFactory=false
        predicates:
        - After=2019-01-20T10:15:47.789+08:00

自定义全局过滤器

gateway有几个默认的全局过滤器,对每一个路由都起作用,不需要配置,默认启用的
自定义全局过滤器需要实现GlobalFilter,Ordered接口

public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getAttribute("token");
        if (token == null || token.isEmpty()) {
            System.out.println("token is empty");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -10;
    }
}

注册到IOC里面

@Bean
    public MyGlobalFilter registryMyGlobelFilter() {
	    return new MyGlobalFilter();
    }

猜你喜欢

转载自blog.csdn.net/zgq_hw/article/details/88248650