springcloud-6.getway网关

简介

Spring Cloud Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器,隐藏微服务结点IP端口信息,从而加强安全保护。Spring Cloud Gateway本身也是一个微服务,需要注册到Eureka服务注册中心。

核心功能: 过滤和路由

D4Au5j.png

核心概念

路由(route): 路由信息的组成:由一个ID、一个目的URL、一组断言工厂、一组Filter组成。如果路由断言为真,说明请求URL和配置路由匹配。
断言(Predicate): Spring Cloud Gateway中的断言函数输入类型是Spring 5.0框架中的ServerWebExchange。Spring Cloud Gateway的断言函数允许开发者去定义匹配来自于Http Request中的任何信息比如请求头和参数。
过滤器(Filter) :一个标准的Spring WebFilter。 Spring Cloud Gateway中的Filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。

快速入门案例

创建itkaoti-getway模块

  • 添加依赖
<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>

  • GetwayApplicationGetwayApplication
@SpringBootApplication
@EnableDiscoveryClient
public class GetwayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GetwayApplication.class, args);
    }
}

  • 配置文件

端口: 10010, 其中routes的配置, 表示 所有通过getway的流量路径符合/user/** 的都会转发到8080端口服务

server:
  port: 10010
spring:
  application:
    name: api-getway
  cloud:
    gateway:
      routes:
        # 路由id
        - id: user-service-route
          # 代理的服务地址
          uri: http://127.0.0.1:8080
          # 路由断言,可以配置映射路径
          predicates:
            - Path=/user/**


# 配置eureka
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    # 配置ip
    ip-address: 127.0.0.1
    # 优先使用ip
    prefer-ip-address: true
    # 一旦超过多长时间, eureka认为服务已经移除或者失效, 默认: 90s
    lease-expiration-duration-in-seconds: 30
    # 服务的续约时间(多久续约一次) 默认:30s
    lease-renewal-interval-in-seconds: 10
  • 启动

我们启动 eureka(10086), user-service(8080) 以及getway(10010),

那么此时我们访问: http://127.0.0.1:10010/user/2 --> http://127.0.0.1:8080/user/2

我们发现访问成功, 请求成功转发到8080端口

入门demo源码地址

面向服务路由

itkaoti-getway

在上面入门工程中, 我们将路由地址是写死是不合理的, 在springcloudgetway, 我们可以通过配置动态路来解决, 我们可以通过服务的名称去uereka中获取。

  • 修改配置文件

将写死的uri修改为如下

uri: lb://user-service
  • 重启getway

访问 http://127.0.0.1:10010/user/2

路由器的前缀处理

有时候我们访问的路径和转发的路由有一定的差异, 比如 getway http://127.0.0.1:10010/api/user/2, 而实际上我们的服务为 http://127.0.0.1:8080/user/2, 那该怎么办呢? 当然有多处前缀, 也有可能路径少一些, 比如: http://127.0.0.1:10010/2, 这个链接直接对应我们的服务。

添加前缀

我们访问 http://127.0.0.1:10010/2 , getway转发请求访问 http://127.0.0.1:8080/user/2

  • 配置文件
spring:
  application:
    name: api-getway
  cloud:
    gateway:
      routes:
        # 路由id
        - id: user-service-route
          # 代理的服务地址
#          uri: http://127.0.0.1:8080
          uri: lb://user-service
          # 路由断言,可以配置映射路径
          predicates:
            - Path=/**
          filters:
            # 添加请求的前缀
            - PrefixPaht=/user
  • 重启测试

访问 http://127.0.0.1:10010/2, 访问ok

去除前缀

我们访问 http://127.0.0.1:10010/api/user/2 , getway转发请求访问 http://127.0.0.1:8080/user/2

  • 修改配置文件
spring:
  application:
    name: api-getway
  cloud:
    gateway:
      routes:
        # 路由id
        - id: user-service-route
          # 代理的服务地址
#          uri: http://127.0.0.1:8080
          uri: lb://user-service
          # 路由断言,可以配置映射路径
          predicates:
            - Path=/api/user/**
          filters:
             # 表示过滤1个路径,2表示两个路径,以此类推
            - StripPrefix=1
  • 重启

访问 http://127.0.0.1:10010/api/user/2, 访问ok

前缀去除和添加源码地址

过滤器

简介

Gateway作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作往往是通过网关提供的过滤器来实现的。前面的 路由前缀 章节中的功能也是使用过滤器实现的。

过滤器官方文档

过滤器类型:Gateway实现方式上,有两种过滤器;局部过滤器 以及 全局过滤器

  • 局部过滤器

通过 spring.cloud.gateway.routes.filters 配置在具体路由下,只作用在当前路由上;自带的过滤器都可以配置或者自定义按照自带过滤器的方式。如果配置spring.cloud.gateway.default-filters 上会对所有路由生效也算是全局的过滤器;但是这些过滤器的实现上都是要实现GatewayFilterFactory接口。

  • 全局过滤器

不需要在配置文件中配置,作用在所有的路由上;实现 GlobalFilter 接口即可。

快速案例

实现添加响应头的过滤器

  • 修改配置文件

这边我们使用AddResponseHeader 过滤器来添加2个响应头

spring:
  application:
    name: api-getway
  cloud:
    gateway:
      routes:
        # 路由id
        - id: user-service-route
          # 代理的服务地址
          uri: lb://user-service
          #添加前缀-*-*-*-*-*-*-*-*
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1
            - AddResponseHeader=X-Response-A, B
            - AddResponseHeader=itkaoti, B
  • 启动

访问 http://127.0.0.1:10010/api/user/2, 访问ok

D481DH.pngD481DH.png

过滤器入门源码地址

自定义局部过滤器

要求

访问http://127.0.0.1:10010/api/user/2 的链接的时候,要求添加token 参数来做用户登录校验, token=123456的时候, 才能返回正确数据,否则返回权限不够的提示。

(可以仿照 AddResponseHeaderGatewayFilterFactory, 来实现)

配置文件

添加TokenCheck=token , springcloud会根据TokenCheck 去查找 TokenCheckGatewayFilterFactory类

spring:
  application:
    name: api-getway
  cloud:
    gateway:
      routes:
        # 路由id
        - id: user-service-route
          # 代理的服务地址
          uri: lb://user-service
          #添加前缀-*-*-*-*-*-*-*-*
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=1
            - AddResponseHeader=X-Response-A, B
            - AddResponseHeader=itkaoti, B
            - TokenCheck=token

TokenCheckGatewayFilterFactory

@Component
public class TokenCheckGatewayFilterFactory extends AbstractGatewayFilterFactory<TokenCheckGatewayFilterFactory.ParamConfig> {
    // 这个必须要加,否则下面apply方法中的config.getParam() 获取为null
    static final String PARAM_NAME = "param";
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(PARAM_NAME);
    }


    // 构造函数必须加, 否则会报类型转换异常
    public TokenCheckGatewayFilterFactory() {
        super(TokenCheckGatewayFilterFactory.ParamConfig.class);
    }

    public static class ParamConfig {
        protected String param;

        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }
    }



    @Override
    public GatewayFilter apply(ParamConfig config) {
        return (exchange, chain) -> {
            // config.getParam() --> 相当于获取到了配置文件中的TokenCheck=token 的值, 也就是token
            // 下面就是获取了token的值
            List<String> strings = exchange.getRequest().getQueryParams().get(config.getParam());
            boolean b = strings.stream().anyMatch(string -> string.equals("123456"));
            if(b){
                return chain.filter(exchange);
            }else{
            	// 这边处理有点问题, 仅仅实现了不让访问
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return  exchange.getResponse().setComplete();
            }
        };
    }
}
  • 启动

访问 http://127.0.0.1:10010/api/user/2?token=123456 正常访问

DoGSNd.png

访问 http://127.0.0.1:10010/api/user/2?token=12345, token不对 正常不了

DoGp4A.png

自定义全局过滤器

编写全局过滤器

/**
 * 全局过滤器, 过滤referer非itkaoti的请求
 */
@Component
public class RefererCheckGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("---------------全局过滤器-------------------");
        String referer = exchange.getRequest().getHeaders().getFirst("referer");
        if(StringUtils.isBlank(referer) || !referer.contains("itkaoti.top")){
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();

        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        // 值越小, 越先执行
        return 1;
    }
}

启动

这个时候, 我们就需要使用postman来伪造 referer 来请求

http://127.0.0.1:10010/api/user/2?token=123456

在我们不添加referer的时候, 请求响应401,

ruRyzq.png

添加referer后, 正常返回请求结果

ruRcQ0.png

getWay的其他参数说明

负载均衡

# 负载均衡
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 2000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 0

熔断配置

# 熔断配置
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000

跨域配置

spring:
  cloud:
    gateway:
     # 跨域设置
      globalcors:
        corsConfigurations:
          '[/**]':
            #allowedOrigins: * # 这种写法或者下面的都可以,*表示全部
            allowedOrigins:
              - "http://*.itkaoti.top"
            allowedMethods:
              - GET

getWay高可用

启动多个getWay, 使用nginx 做负载均衡

过滤器和其他配置参数源码