Gateway(拦截器/路由)

Gateway 核心是一系列的过滤器 主要作用 过滤和路由
整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息
Geteway本身就是一个微服务,需要注册到Eureka中心
不管是来自于客户端(PC或移动端)的请求,还是服务内部调用,一切服务的请求都可以经过网关
实现鉴权 动态路由 服务的统一入口
在这里插入图片描述

1.使用Gateway

拦截请求中带 /users/ 的请求
拦截http://localhost:10086/users/2 — 跳转到------->http://localhost:8081
1.添加依赖 pom.xml

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

          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
          </dependency>
      </dependencies>


2.在启动类添加注解
@EnableDiscoveryClient //启用Gateway

@SpringBootApplication
@EnableDiscoveryClient   //启用Gateway
public class Demo04GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(Demo04GatewayApplication.class,args);
    }
}

3.配置.properties文件
拦截的请求类型spring.cloud.gateway.routes[0].predicates[0]=Path=/users/**

# service name
spring.application.name=demo04-gateway
#port
server.port=10086
# 找到Eureka的地址
eureka.client.service-url.defaultZone=http://localhost:8083/eureka,http://localhost:8084/eureka

# 路由id
spring.cloud.gateway.routes[0].id=demo04_gateway_1001
# provider的一个服务地址,就是拦截到之后跳到的地址
spring.cloud.gateway.routes[0].uri=http://localhost:8081
# 拦截的断言  要拦截带有/**的url
spring.cloud.gateway.routes[0].predicates[0]=Path=/users/**

4.测试

输入http://localhost:10086/users/1 转到http://localhost:8081/users/1拿到该provider的返回的结果

2.动态路由(面向服务的路由:之前把服务地址写死是不合理的,所以就要使用动态路由)

以(lb://lb://user-service为例)
原理:Gateway通过LoadBalanceClient把user-service通过Eureka解析成具体的host和端口,并进行负载均衡

使用在Eureka中注册的服务作为路由地址,而不是写死的地址
动态路由(面向服务的路由):在配置文件中指定路由路径类似于:
lb://lb://user-service

3.路由前缀处理 filter(对请求到网关的服务地址添加或者去除前缀)

请求地址与微服务的服务地址如果不一致的时候,可以通过配置路径过滤器实现路径前缀的添加和去除
添加
http://localhost:10086/3->http://localhost:10086/users/3

# 添加前缀
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
# 添加前缀 在客户端的请求地址上添加/users
 spring.cloud.gateway.routes[0].filters[0]=PrefixPath=/users

减少
http://localhost:10086/api/users/3->http://localhost:10086/users/3

#  减少前缀 在客户端的请求地址上减少前缀
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/users/**
# 1表示去除一前缀,2表示两个,一次类推
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1

4.过滤器(请求鉴权、异常处理、记录调用时长)

1.介绍
1.符合条件的请求放行,否则不放行

# 默认过滤器   spring.cloud.gateway.default-filters对所有的路由都生效
spring.cloud.gateway.default-filters[0]=AddResponseHeader=name,rose
spring.cloud.gateway.default-filters[1]=AddResponseHeader=age,34


在这里插入图片描述
2.过滤器分为两种
1)局部过滤器
只对当前路由起作用
1)spring.cloud.gateway.routes.filters

2)全局过滤器
作用在所有的路由上
1)spring.cloud.gateway.default-filters + 实现GatewayFilterFactory接口的过滤器
2) 实现GlobalFilter接口,不需要配置

2.自定义全局过滤器(判断url中是否有token参数,可以用于判断user对象是否为空)
1.实现接口
GlobalFilter接口 重写filter方法 拿到token,判断token是否为空,不为空则放行,如果token为null或者不存在则设置返回的状态码为:未授权
Order接口 重写getOrder()方法 系统调用该方法获得过滤器的优先级,返回的数字越小优先级越高
2.编写filter方法中的逻辑

package com.zx.demo04gateway.filter;


@Component
@Slf4j
public class MyParamGlobalFilter implements GlobalFilter , Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //拦截方法,拦截到请求后,自动执行
        log.info("filter 拦截方法,拦截到请求后,自动执行 ");
        //以后开发中,不会将 user对象存到session,只会在地址上带上token
        //根据token是否有空可以判断是否登录
        //http://localhost:8001/users/3?token=10001&pageSize=30
        String token =  exchange.getRequest().getQueryParams().getFirst("token");
        if(token == null || "".equals(token)){
            //未登录 跳转到登录页
            log.info("----跳到登录页面");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);//2 全部放行
    }

    @Override
    public int getOrder() {
        //3:系统调用该方法获得过滤器的优先级
        return 1; //数字越小,越优先
    }
}


3.自定义局部过滤器(请求鉴权、异常处理、记录调用时长)
1.添加局部过滤器配置

spring.cloud.gateway.routes[0].filters[1]=MyParam=name,address

2.继承AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> 抽象类
重写apply方法

3.编写静态内部类Config 要拦截的参数名

  @Data
    public static class Config{
        private String name;
        private String address;
    }

4.将config交给父类的构造方法

public MyParamGatewayFilterFactory() {
        super(Config.class);
    }

5.编写shortcutFieldOrder()方法,定义变量顺序

@Override
    public List<String> shortcutFieldOrder() {//定义变量的顺序
        List<String> order = new ArrayList<>();
        order.add("name");
        order.add("address");
        return order;
    }

6.编写重写的apply方法
因为返回的类型是一个接口 GatewayFilter,所以还要定义一个类(直接实例化接口,重写方法)来实现GatewayFilter接口,重写其中的 filter()方法

public GatewayFilter apply(Config config) {
        GatewayFilter gatewayFilter = new GatewayFilter(){

            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //http://localhost:10086/api/users/1?token=1&name=jack&address=zs
                String name = exchange.getRequest().getQueryParams().getFirst(config.name);
                String address = exchange.getRequest().getQueryParams().getFirst(config.address);
                log.info("filter ....name"+name);
                log.info("filter ....address"+address);
                log.info("filter ....拦截了请求");
                return chain.filter(exchange);//全部放行
            }
        };
        return gatewayFilter;//返回一个自己定义的过滤器
    }

7.全部的MyParamGatewayFilterFactory类

package com.zx.demo04gateway.filter;

@Component
@Slf4j
public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {
    //5:将config交给父类的构造方法
    public MyParamGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        GatewayFilter gatewayFilter = new GatewayFilter(){

            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //http://localhost:10086/api/users/1?token=1&name=jack&address=zs
                String name = exchange.getRequest().getQueryParams().getFirst(config.name);
                String address = exchange.getRequest().getQueryParams().getFirst(config.address);
                log.info("filter ....name"+name);
                log.info("filter ....address"+address);
                log.info("filter ....拦截了请求");
                return chain.filter(exchange);//全部放行
            }
        };
        return gatewayFilter;//返回一个自己定义的过滤器
    }

    //3:定义顺序
    @Override
    public List<String> shortcutFieldOrder() {//定义变量的顺序
        List<String> order = new ArrayList<>();
        order.add("name");
        order.add("address");
        return order;
    }

    //2:定义config  name,address
     //http://localhost:10086/api/users/1?token=1&name=jack&address=zs
    @Data
    public static class Config{
        private String name;
        private String address;
    }
}


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐