SpringCloud之Gateway服务网关

429 阅读6分钟

yml配置网关路由

Gateway网关路由有两种配置方式,一种用yml配置

新建cloud-gateway-gateway9527模块

image-20200709141933347

pom

不要引入spring web依赖,否则启动不了

<dependencies>
    <!--新增gateway-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>com.kylin</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

yml

image-20200709142451333

server:
  port: 9527
spring:
  application:
    name: cloud-gateway


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

主启动类

创建主启动类GateWayMain9527

image-20200709142632928

@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run( GateWayMain9527.class,args);
    }
}

新增网关配置

我们目前不想暴露8001端口,希望在8001外面套一层9527

cloud-provider-payment8001的两个方法做路由映射

image-20200709143010584

image-20200709143148659

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
      - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
        uri: http://localhost:8001   #匹配后提供服务的路由地址
        predicates:
          - Path=/payment/get/**   #断言,路径相匹配的进行路由

      - id: payment_routh2
        uri: http://localhost:8001
        predicates:
          - Path=/payment/lb/**   #断言,路径相匹配的进行路由


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

测试

启动7001 8001 9527 http://eureka7001.com:7001/成功注册到Eureka注册中心

image-20200709143716103

访问http://localhost:8001/payment/get/31

image-20200709143845573

访问http://localhost:9527/payment/get/31,也能访问成功

image-20200709143919448

访问http://localhost:9527/payment/lb

dimage-20200709144122986

编码码配置网关路由

Gateway网关路由有两种配置方式,一种用编码配置

我们想通过9527网关访问到外网的百度新闻网址

配置类

编写配置类GateWayConfig

image-20200709144911754

@Configuration
public class GateWayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        routes.route("path_rote_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
        return routes.build();
    }
}

测试

重新启动9527,访问http://localhost:9527/guonei

GIF转存失败,建议直接上传图片文件

实现动态路由

我们当前的路由映射是将地址写死了

image-20200709150148528

而我们应该要达到的效果是同以前一样,通过访问微服务提供者的服务命调用所提供的服务,尽管这个微服务是一个集群。这些客户端都不关心,所以我们要配置GateWay通过微服务名实现动态路由。

yml

image-20200709150555182

通过配置spring.cloud.gateway.discovery.locator.enabled开启从注册中心动态创建路由的功能,利用微服务名进行路由,默认false

此时的spring.cloud.gateway.routeslist集合中的uri属性值为lb://serviceNameuri的协议为lb,表示启用Gateway的负载均衡功能。serviceName时注册中心注册的名称

server:
  port: 9527
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #uri的协议为lb,表示启用Gateway的负载均衡功能。
          predicates:
            - Path=/payment/get/**   #断言,路径相匹配的进行路由

        - id: payment_routh2
          #uri: http://localhost:8001   #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #uri的协议为lb,表示启用Gateway的负载均衡功能。
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由


eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

测试

启动7001 8001 8002 9525 访问http://localhost:9527/payment/lb

image-20200709151102797

GIF1511

动态路由配置成功!

Predicate的使用

当我们启动的我们9527的时候会看见控制台输出

image-20200709151428142

我们之前使用Predicate是属性名是predicates说明它能配置多个匹配条件,而我们目前只匹配了Path条件

image-20200709151558412

Route Predicate Factorie

查看官网cloud.spring.io/spring-clou…

image-20200709151832266

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的路由谓词工厂。

Spring Cloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。

所有这些谓词都与HTTP请求的不同属性匹配。您可以将多个路由谓词工厂与逻辑and语句结合使用。

常用的Predicate

image-20200709152504391

After Route Predicate Factory

请求时间满足在配置时间之后

这个时间怎么获得呢?

通过Java提供的ZonoeDateTime.now()获得当地的时间

image-20200709153020096

After=时间 我们把时间改为自己当地的时间后一分钟进行测试

重新启动测试,访问http://localhost:9527/payment/get/31此时再配置时间之前。报错404

image-20200709153445315

配置时间之后在访问,一切正常

image-20200709153358612

同理Before Between也是一样的配置和使用

Cookie Route Predicate Factory

配置文件predicates加上Cookie

image-20200709154112849

Cookie=username,kylin 只允许cookie键为username 值为kylin

通过命令行curl http://localhost:9527/payment/lb访问

image-20200709154219529

不符合条件报错404

加上cookie访问curl http://localhost:9527/payment/lb --cookie "username=kylin"

image-20200709154447402

访问成功!一切正常

Header Route Predicate Factory

image-20200709154933382

Header=X-Request-Id, \d+ 请求头要有X-Request-Id属性并且值为整数的正则表达式

访问curl http://localhost:9527/payment/lb -H "X-Request-Id:123"值为整数,一切正常

image-20200709155106342

值为负数curl http://localhost:9527/payment/lb -H "X-Request-Id:-123"

image-20200709155144640

报错404,配置成功!

说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理

Filter的使用

cloud.spring.io/spring-clou…

image-20200709161254014

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway内置了多种路由过滤器,他们都有GatewayFilter的工厂类来产生

Filter的声明周期只有两个“pre” 和 “post”。“pre”和 “post” 分别会在请求被执行前调用和被执行后调用。种类分为单一的,和全局的。

Filter,在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出、流量监控等,有非常重要的作用

Filter除了分为“pre”和“post”两种方式的Filter外,在Spring Cloud Gateway中,Filter从作用范围可分为另外两种,一种是针对于单个路由的Gateway Filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的Global Gateway Filer。现在从作用范围划分的维度来讲解这两种Filer。

单一过滤器GatewayFilter

cloud.spring.io/spring-clou…

全局GlobalFilter

cloud.spring.io/spring-clou…

image-20200709165641947

自定义全局过滤器

Gateway提供好的过滤器并没有太大的意义,我们可以自定义过滤器编写业务逻辑

将我们配置Predicate注释,编写MyLogGateWayFilter实现GlobalFilter, Ordered,判断是否带有uname参数不能为null


@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("*************come in MyLogGateWayFilter:"+new Date());
        //带有uname的请求参数
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname==null){
            log.info("********用户名为null,非法用户,/(ㄒoㄒ)/~~");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//添加响应状态码
            return exchange.getResponse().setComplete();
        }
        //放行
        return chain.filter(exchange);
    }

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

启动7001 8001 8002 9527进行测试直接访问http://localhost:9527/payment/lb,访问不拦截

image-20200709165257427

http://localhost:9527/payment/lb?uname=kylin加上uanme参数且值不为null

image-20200709165342802

image-20200709165411114

访问成功!