SpringCloud——中级(二)服务网关Gateway

Gateway新一代网关

一、概述简介

1、官网

上一代zuul 1.X官网
当前的gateway

2、是什么

gateway是原zuul1.x版的替代版
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等。
在这里插入图片描述
SpringCloud Gateway使用的Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架

3、能干嘛

反向代理、鉴权、流量控制、熔断、日志监控

4、微服务架构中网关在哪里

在这里插入图片描述

5、有Zuul了怎么又出来了gateway

Gateway具有以下特性:
基于Spring Framework 5,Project Reactor 和Spring Boot 2.0进行构建
动态路由:能够匹配任何请求属性;
可以对路由指定Predicate(断言)和Filter(过滤器);
集成Hystrix 的断路器功能;
集成Spring Cloud 服务发现功能;
易于编写的Predicate(断言)和Filter(过滤器);
请求限流功能;
支持路径重写;
在这里插入图片描述
Gateway底层使用WebFlux+Netty 非阻塞异步的框架

二、三大核心概念

1、Route(路由)

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

2、Predicate(断言)

参考的是Java8的java.util.function.Predicatee
开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由

3、Filter(过滤)

指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。

4、总体

匹配方式就叫断言,实现这个匹配方式就叫filter,对外表现出来就是路由的功能。
在这里插入图片描述
web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制predicate就是我们的匹配条件;
而 filter,就可以理解为个无所不能的拦截器。有了这两个元素,再加上目标u。就可以实现一个具体的路由了

三、Gateway工作流程

1、官网总结

在这里插入图片描述
客户端向 Spring Cloud Gateway发出请求。然后在 Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到 GatewayWeb Handler。

Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回
过滤器之间用虛线分开是因为过滤器可能会在发送代理请求之前("pre”)或之后("post”)执行业务逻辑。

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

2、核心逻辑

路由转发+执行过滤器链

四、入门配置

1、新建Model

cloud-gateway-gateway9527

2、pom

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

3、yml

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

eureka:
  instance:
    hostname: cloud-gateway-serrvice
  client:     #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

4、业务类

无。。。

5、主启动类

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

6、9527网关如何做路由映射

1)cloud-provider-payment8001看看controller的访问地址

get、lb

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

7、YML新增网关配置

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

        - id: payment_routh2 #payment_route   #路由的ID,没有固定规则但要求唯一,建议配合服务名
            uri: http://localhost:8001  #匹配后提供服务的路由地址
            predicates:
              - Path=/payment/lb/**   #断言,路径相匹配的进行路由

eureka:
  instance:
    hostname: cloud-gateway-serrvice
  client:     #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

8、测试

1)启动7001

2)启动8001

3)启动9527网关

4)访问说明

http://localhost:8001/payment/lb

http://localhost:9527/payment/lb

9、YML配置说明

Gateway网关路由有两种配置方式:
1、yml文件中配置,见上。。
2、代码中注入RouteLocator的Bean(硬编码)
自己写一个:通过9527网关访问到外网的百度新闻网址
http://news.baidu.com/guonei
配置代码如下:

package com.atguigu.springcloud.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayConfig {
    /*
    * 配置了一个id为route_name的路由规则
    * 当访问地址:localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei
    * */
    @Bean
    public RouteLocator customrouts(RouteLocatorBuilder routeLocatorBuilder){

        RouteLocatorBuilder.Builder routes=routeLocatorBuilder.routes();

        routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();

        return routes.build();
    }
}

测试:http://localhost:9527/guonei
可以成功访问

五、通过微服务名实现动态路由

1、实现方式

默认情况下 Gateway会根据注册中心注册的服务列表,
以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

2、启动:7001、8001/8002

3、pom

4、YML

注意:
uri协议为lb,表示启用Gateway的负载均衡功能。
Ib: //servicename spring cloudgateway在微服务中自动为我们创建的负载均衡uri

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

        - id: payment_routh2 #payment_route   #路由的ID,没有固定规则但要求唯一,建议配合服务名
         # uri: http://localhost:8001  #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由

eureka:
  instance:
    hostname: cloud-gateway-serrvice
  client:     #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

5、测试

http://localhost:9527/payment/lb
8001和8002两个端口切换

六、Predicate的使用

1、是什么

2、Route Predicate Factories这个是什么

详见官网:官网
在这里插入图片描述

3、常用的Route Predicate

在这里插入图片描述

1)关于时间的

After Route Predicate
Before Route Predicate
Between Route Predicate

        - id: payment_routh2 #payment_route   #路由的ID,没有固定规则但要求唯一,建议配合服务名
         # uri: http://localhost:8001  #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由
            - After=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]
            - Before=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]

2)Cookie Route Predicate

Cookie route predicate需要两个参数,一个是 Cookie name,个是正则表达式。
路由规则会通过获取对应的 Cookie name值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行

        - id: payment_routh2 #payment_route   #路由的ID,没有固定规则但要求唯一,建议配合服务名
         # uri: http://localhost:8001  #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**   #断言,路径相匹配的进行路由
            - After=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]
            - Before=2020-04-06T14:29:45.412+08:00[Asia/Shanghai]
            - Cookie=username,zzyy

使用curl测试:
不带cookie访问:

curl http://localhost:9527/payment/lb

带cookie访问:

curl http://localhost:9527/payment/lb --cookie "username=zzyy"

在这里插入图片描述

3)Header

yml文件中:

- Header=X-Request-Id,/d+ #请求头要有X-Request-Id属性并且值为整数的正则表达式
curl http://localhost:9527/payment/lb -H "X-Request-id:123

在这里插入图片描述

4)Method

yml文件中:

- Method=GET

5)小总结

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

七、Filter的使用

1、是什么

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。
Spring Cloud Gateway内置了多种路由过滤器,他们都由 Gateway Filter的工厂类来产生

2、Spring Cloud Gateway的Filtere

1)生命周期,Only Two

pre、post

2)种类,Only Two

1.GatewayFilter:官网描述

2.GlobalFilter

3、常用的GatetwayFilter

AddRequestParameter:

          filters:
            - AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的头加上一对清求头,客称为X-Request-Id值为024

4、自定义过滤器

自定义全局GlobalFilter:

1)两个主要接口介绍

implements GlobalFilter,Ordered

2)能干嘛

全局日志记录
统一网关鉴权

3)案例代码

package com.atguigu.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("********come in MyLogGateWayFilter:  "+new Date());
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if(uname==null){
            log.info("****用户名为空null,非法用户!!");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

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

4)测试

启动:7001、8001、8002、9527
地址:localhost:9527/payment/lb?uname=z3
localhost:9527/payment/lb

发布了20 篇原创文章 · 获赞 4 · 访问量 7296

猜你喜欢

转载自blog.csdn.net/qq_41307492/article/details/105340544