Spring Cloud 系列之GateWay(网关)

GateWay简介

     Spring Cloud GateWay是Spring Cloud的一个全新项目,目标是取代Netflix Zuul,它基于Spring5.0+SpringBoot2.0+WebFlux(基于高性能的Reactor模式响应式通信框架Netty,异步非阻塞模型)等技术开发,性能高于Zuul,官方测试,GateWay是Zuul的1.6倍,旨在为微服务架构提供一种简单有效的统一的API路由管理方式。

     Spring Cloud GateWay不仅提供统一的路由方式(反向代理)并且基于 Filter(定义过滤器对请求过滤,完成一些功能) 链的方式提供了网关基本的功能,例如:鉴权、流量控制、熔断、路径重写、日志监控等。

GateWay核心概念

 Spring Cloud GateWay天生就是异步非阻塞的,基于Reactor模型(同步非阻塞的I/O多路复用机制)。

一个请求—>网关根据一定的条件匹配—匹配成功之后可以将请求转发到指定的服务地址;而在这个过程中,我们可以进行一些比较具体的控制(限流、日志、黑白名单)。

路由(route): 网关最基础的部分,也是网关比较基础的工作单元。路由由一个ID、一个目标URL(最终路由到的地址)、一系列的断言(匹配条件判断)和Filter过滤器(精细化控制)组成。如果断言为true,则匹配该路由。

断言(predicates):参考了Java8中的断言java.util.function.Predicate,开发人员可以匹配Http请求中的所有内容(包括请求头、请求参数等)(类似于nginx中的location匹配一样),如果断言与请求相匹配则路由。

过滤器(filter):一个标准的Spring webFilter,使用过滤器,可以在请求之前或者之后执行业务逻辑。

网关在架构中的位置

  

GateWay网关组件

网关:微服务架构中的重要组成部分 。

局域网中就有网关这个概念,局域网接收或者发送数据出去通过这个网关,比如用Vmware虚拟机软件搭建虚拟机集群的时候,往往我们需要选择IP段中的一个IP作为网关地址。

我们学习的GateWay-->Spring Cloud GateWay(它只是众多网关解决方案中的一种)

GateWay如何工作

 

GateWay应用

   使用网关对静态化微服务进行代理(添加在它的上游,相当于隐藏了具体微服务的信息,对外暴露的是网关)。

  1.创建工程yang-cloud-gateway-server导入依赖

  GateWay不需要使用web模块,它引入的是WebFlux(类似于SpringMVC)

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0

http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>com.yang</groupId>

  <artifactId>yang-cloud-gateway</artifactId>

  <version>1.0-SNAPSHOT</version>

  <!--spring boot 父启动器依赖-->

  <parent>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-parent</artifactId>

    <version>2.1.6.RELEASE</version>

  </parent>

  <dependencies>

    <dependency>

      <groupId>org.springframework.cloud</groupId>

      <artifactId>spring-cloud-commons</artifactId>

    </dependency>

    <dependency>

      <groupId>org.springframework.cloud</groupId>

      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

    </dependency>

    <!--GateWay 网关-->

    <dependency>

      <groupId>org.springframework.cloud</groupId>

      <artifactId>spring-cloud-starter-gateway</artifactId>

    </dependency>

    <!--引入webflux-->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-webflux</artifactId>

    </dependency>

    <!--日志依赖-->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-logging</artifactId>

    </dependency>

    <!--测试依赖-->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-test</artifactId>

      <scope>test</scope>

    </dependency>

    <!--lombok工具-->

    <dependency>

      <groupId>org.projectlombok</groupId>

      <artifactId>lombok</artifactId>

      <version>1.18.4</version>

      <scope>provided</scope>

</dependency>

<!--引入Jaxb,开始-->

    <dependency>

      <groupId>com.sun.xml.bind</groupId>

      <artifactId>jaxb-core</artifactId>

      <version>2.2.11</version>

    </dependency>

    <dependency>

      <groupId>javax.xml.bind</groupId>

      <artifactId>jaxb-api</artifactId>

    </dependency>

    <dependency>

      <groupId>com.sun.xml.bind</groupId>

      <artifactId>jaxb-impl</artifactId>

      <version>2.2.11</version>

    </dependency>

    <dependency>

      <groupId>org.glassfish.jaxb</groupId>

      <artifactId>jaxb-runtime</artifactId>

      <version>2.2.10-b140310.1920</version>

    </dependency>

    <dependency>

      <groupId>javax.activation</groupId>

      <artifactId>activation</artifactId>

      <version>1.1.1</version>

    </dependency>

    <!--引入Jaxb,结束-->

    <!-- Actuator可以帮助你监控和管理Spring Boot应用-->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-actuator</artifactId>

    </dependency>

    <!--热部署-->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-devtools</artifactId>

      <optional>true</optional>

    </dependency>

    <!--链路追踪-->

    <dependency>

      <groupId>org.springframework.cloud</groupId>

      <artifactId>spring-cloud-starter-sleuth</artifactId>

    </dependency>

    <dependency>

      <groupId>org.springframework.cloud</groupId>

      <artifactId>spring-cloud-starter-zipkin</artifactId>

    </dependency>

  </dependencies>

  <dependencyManagement>

    <!--spring cloud依赖版本管理-->

    <dependencies>

      <dependency>

        <groupId>org.springframework.cloud</groupId>

        <artifactId>spring-cloud-dependencies</artifactId>

<version>Greenwich.RELEASE</version>

        <type>pom</type>

        <scope>import</scope>

      </dependency>

    </dependencies>

  </dependencyManagement>

  <build>

    <plugins>

      <!--编译插件-->

      <plugin>

        <groupId>org.apache.maven.plugins</groupId>

        <artifactId>maven-compiler-plugin</artifactId>

        <configuration>

          <source>11</source>

          <target>11</target>

          <encoding>utf-8</encoding>

        </configuration>

      </plugin>

      <!--打包插件-->

      <plugin>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-maven-plugin</artifactId>

      </plugin>

    </plugins>

  </build>

</project>

注意:不要引入starter-web模块,需要引入web-flux。

2.application.yml 配置文件内容

server:

port: 9300

eureka:

client:

 serviceUrl: # eureka server的路径

  defaultZone:

http://YangCloudEurekaServerA:9200/eureka,http://YangCloudEurekaServerB:9201/e

ureka

instance:

 prefer-ip-address: true

 instance-id: ${spring.cloud.client.ip-

address}:${spring.application.name}:${server.port}:@project.version@

spring:

application:

 name: yang-cloud-gateway

 #网关的配置

cloud:

 gateway:

  routes: #配置路由

   - id: service-page-router

    uri: http://127.0.0.1:9100

    predicates: #当断言成功后,交给某一个微服务处理时使用的是转发

     - Path=/page/**

- id: service-product-router

    uri: http://127.0.0.1:9000

    predicates:

     - Path=/product/**

    filters:

      # http://127.0.0.1:9300/product/service/port --> /service/port -->

商品微服务

     - StripPrefix=1  #去掉uri中的第一部分,所以就要求我们通过网关访问的时候,把uri

的第一部分设置为product,从uri的第二部分开始才是真正的uri

                                                                            

 

                                                                        

 

 

 

                                                                        

3,启动类

package com.yang.gateway;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication

@EnableDiscoveryClient

public class GatewayApplication {

  public static void main(String[] args) {

    SpringApplication.run(GatewayApplication.class,args);

 }

}

4.测试

http://127.0.0.1:9501/page/getData/1

http://127.0.0.1:9501/product/product/query/1

GateWay路由规则详解

   Spring Cloud GateWay 帮我们内置了很多 Predicates功能,实现了各种路由匹配规则(通过Header、请求参数等作为条件)匹配到对应的路由。

 

时间点后匹配

spring:

cloud:

 gateway:

  routes:

   - id: after_route

    uri: https://example.org

    predicates:

     - After=2017-01-20T17:42:47.789-07:00[America/Denver]

时间点前匹配

spring:

cloud:

 gateway:

  routes:

  - id: before_route

   uri: https://example.org

   predicates:

   - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

时间区间匹配

spring:

cloud:

 gateway:

  routes:

  - id: between_route

   uri: https://example.org

   predicates:

   - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-

21T17:42:47.789-07:00[America/Denver]

指定Cookie正则匹配指定值

spring:

cloud:

 gateway:

  routes:

  - id: cookie_route

   uri: https://example.org

   predicates:

   - Cookie=chocolate, ch.p

指定Header正则匹配指定值

spring:

cloud:

 gateway:

  routes:

  - id: header_route

   uri: https://example.org

   predicates:

   - Header=X-Request-Id, \d+

请求Host匹配指定值

spring:

cloud:

 gateway:

  routes:

  - id: host_route

   uri: https://example.org

   predicates:

   - Host=**.somehost.org,**.anotherhost.org

请求Method匹配指定请求方式

spring:

cloud:

 gateway:

  routes:

  - id: method_route

   uri: https://example.org

   predicates:

   - Method=GET,POST

请求路径正则匹配

spring:

cloud:

 gateway:

  routes:

  - id: path_route

   uri: https://example.org

   predicates:

   - Path=/red/{segment},/blue/{segment}

 

请求包含某参数

spring:

cloud:

 gateway:

  routes:

  - id: query_route

   uri: https://example.org

   predicates:

   - Query=green

请求包含某参数并且参数值匹配正则表达式

spring:

cloud:

 gateway:

  routes:

  - id: query_route

   uri: https://example.org

   predicates:

   - Query=red, gree.

远程地址匹配

spring:

cloud:

 gateway:

  routes:

  - id: remoteaddr_route

   uri: https://example.org

   predicates:

   - RemoteAddr=192.168.1.1/24

GateWay动态路由详解

GateWay支持自动从注册中心中获取服务列表并访问,即所谓的动态路由

实现步骤如下

1)pom.xml中添加注册中心客户端依赖(因为要获取注册中心服务列表,eureka客户端已经引入)

2)动态路由配置

application:
    name: yang-cloud-gateway
  #网关的配置
  cloud:
    gateway:
      routes: #配置路由
        - id: service-page-router
          #动态路由:从注册中心获取对应服务的实例
          uri: lb://yang-service-page
          predicates:
            - Path=/page/**
        - id: service-product-router
          uri: lb://yang-service-product
          predicates:
            - Path=/product/**
          filters:
            - StripPrefix=1

 

注意:动态路由设置时,uri以 lb: //开头(lb代表从注册中心获取服务),后面是需要转发到的服务名称

GateWay过滤器

GateWay过滤器简介

从过滤器生命周期(影响时机点)的角度来说,主要有两个pre和post:

生命周期时机点

作用

pre

这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选

择 请求的微服务、记录调试信息等。

Post

这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP

Header、收集统计信息和指标、将响应从微服务发送给客户端等。

从过滤器类型的角度,Spring Cloud GateWay的过滤器分为GateWayFilter和GlobalFilter两种。

过滤器类型

影响范围

GateWayFilter

应用到单个路由路由上

GlobalFilter 

应用到所有的路由上

如Gateway Filter可以去掉url中的占位后转发路由,比如

predicates:

   - Path=/product/**

   filters:

   - StripPrefix=1  # 可以去掉product之后转发

注意:GlobalFilter全局过滤器是程序员使用比较多的过滤器,我们主要讲解这种类型

自定义全局过滤器实现IP访问限制(黑白名单)

请求过来时,判断发送请求的客户端的ip,如果在黑名单中,拒绝访问。

自定义GateWay全局过滤器时,我们实现Global Filter接口即可,通过全局过滤器可以实现黑白名单、限流等功能。

package com.yang.gateway;

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.core.io.buffer.DataBuffer;

import org.springframework.http.HttpStatus;

import org.springframework.http.server.reactive.ServerHttpRequest;

import org.springframework.http.server.reactive.ServerHttpResponse;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

import java.util.ArrayList;

import java.util.List;

/**

* 定义全局过滤器,会对所有路由生效

*/

@Slf4j

@Component  // 让容器扫描到,等同于注册了

public class BlackListFilter implements GlobalFilter, Ordered {

  // 模拟黑名单(实际可以去数据库或者redis中查询)

  private static List<String> blackList = new ArrayList<>();

  static {

    blackList.add("0:0:0:0:0:0:0:1");  // 模拟本机地址

    blackList.add("127.0.0.1");

 }

  /**

  * 过滤器核心方法

  * @param exchange 封装了request和response对象的上下文

  * @param chain 网关过滤器链(包含全局过滤器和单路由过滤器)

  * @return

  */

  @Override

  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain

chain) {

    System.out.println("....BlackListFilter....");

// 思路:获取客户端ip,判断是否在黑名单中,在的话就拒绝访问,不在的话就放行

 

 // 从上下文中取出request和response对象

    ServerHttpRequest request = exchange.getRequest();

    ServerHttpResponse response = exchange.getResponse();

    // 从request对象中获取客户端ip

    String clientIp = request.getRemoteAddress().getHostString();

    // 拿着clientIp去黑名单中查询,存在的话就决绝访问

    if(blackList.contains(clientIp)) {

      // 决绝访问,返回

      response.setStatusCode(HttpStatus.UNAUTHORIZED); // 状态码

      log.info("=====>IP:" + clientIp + " 在黑名单中,将被拒绝访问!");

      String data = "Request be denied!";

      DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());

      return response.writeWith(Mono.just(wrap));

   }

    // 合法请求,放行,执行后续的过滤器

    return chain.filter(exchange);

 }

  /**

  * 返回值表示当前过滤器的顺序(优先级),数值越小,优先级越高

  * @return

  */

  @Override

  public int getOrder() {

    return 0;

 }

}

GateWay高可用

网关作为非常核心的一个部件,如果挂掉,那么所有请求都可能无法路由处理,因此我们需要做GateWay的高可用。

GateWay的高可用很简单:可以启动多个GateWay实例来实现高可用,在GateWay的上游使用Nginx等负载均衡设备进行负载转发以达到高可用的目的。

  启动多个GateWay实例(假如说两个,一个端口9002,一个端口9003),剩下的就是使用Nginx等完成负载代理即可。示例如下:

#配置多个GateWay实例

upstream gateway {

server 127.0.0.1:9002;

server 127.0.0.1:9003;

}

location / {

proxy_pass http://gateway;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值