SpringCloud Gateway微服务网关介绍快速入门教程案例

概述

什么是Gateway

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring5,SpringBoot2和Project Reactor等技术。
Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤功能,例如:熔断、限流、重试等。

该项目提供了一个用于在Spring WebFlux之上构建API网关的库。

Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到API,并为它们提供跨领域的关注,例如:安全性,监视/指标和弹性。

Gateway的特性

  1. 基于Spring Framework5,Project Reactor和Spring Boot 2.0进行构建;
  2. 动态路由:能够匹配任何请求属性;
  3. 可以对路由指定Predicate (断言) 和Filter (过滤器);
  4. 集成Hystrix的断路器功能;
  5. 集成SpringCloud服务发现功能;
  6. 基于编写的Predicate (断言) 和Filter (过滤器);
  7. 请求限流功能;
  8. 支持路径重写;

Gateway在微服务架构中的地位

image-20201214184100009

Gateway网关的三大组件

  • Route (路由)

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

  • Predicate (断言)

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

  • Filter (过滤)

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

Web请求时,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化的控制,predicate就是我们的匹配条件;而filter,就可以理解为一个无所不能的拦截器,有了这两个元素,再加上目标URI,就可以实现一个具体的路由了。

Gateway的工作流程

image-20201214232219505

总结 路由转发+执行过滤链

Gateway的配置案例

为什么需要引入gateway?

引入gateway后,我们可以在服务模块前加上一层屏障,这样我们暴露给外界的端口只有网关端口,保障了数据的安全性。

1、建Module

cloud-gateway-gateway9527

2、改pom

<dependencies>

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

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

    <!--删除掉entities后,将公用代码打包放到公共模块中,引入模块-->
    <dependency>
        <groupId>com.lejia.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </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>

ps:如果出现错误,可能是将web模块引入到了pom中

3、写yml

server:
  port: 9527

spring:
  application:
    name: cloud-gateway

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

4、主启动

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

5、业务类

6、启动Gateway

Gateway的详细配置

在我们设置好gateway的基本配置后,我们需要根据实际的情况来将gateway设置到我们的服务上

1、使用配置类的方式添加网关路由

根据官网案例

image-20201214235752537

package com.lejia.springcloud.config;

创建配置类GatewayConfig.java

添加方法并注册

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customerLocator(RouteLocatorBuilder routeLocatorBuilder){

        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();

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

}

测试

http://localhost:9527/guonei

image-20201215000135682

ps:因为百度新闻页面使用的是uri,如果想要在测试连接中正确跳转页面的话,需要在添加一个customerLocator,并将路径设置成为百度对应的uri

2、使用yml配置

1、在8001服务外层加上一层9527网关

在yml中添加配置

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

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

测试:

http://localhost:9527/payment/get/1

image-20201214235027851

http://localhost:9527/payment/lb

image-20201214235046042

成功调用到方法!

2、通过微服务名来调用服务提供者集群服务(8001/8002)

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

修改yml文件

主要修改位置:将uri单路径更换为了服务名

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

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

测试

http://localhost:9527/payment/get/1

image-20201215001134312

image-20201215001144375

可以看出默认以轮询规则作为负载均衡策略

Predicate详解

当我们启动Gateway网关服务时,我们可以从输出日志中看到RoutePredicateFactory类的加载

image-20201215001824033

Route Predicate Factory是什么?与predicate又有何关联?

SpringCloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。
SpringCloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配,多个Route Predicate工厂进行组合。
SpringCloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。SpringCloud Gateway包含许多内置的Route Predicate Factories。
所有这些谓词都匹配HTTP请求的不同属性,多种谓词工厂可以组合,并通过逻辑and。

常用的Route Predicate

1、The After Route Predicate Factory

所述After路线谓词工厂有一个参数,一个datetime(其是Java ZonedDateTime)。该谓词匹配在指定日期时间之后发生的请求。

image-20201215003010189

测试:

http://localhost:9527/payment/get/1

在00:27:50之前进行请求

image-20201215002610580

image-20201215002754508

请求不成功,此时虽然路径匹配,但是由于断言其他规则不满足,所以此路由不会进行匹配


在00:27:50之后进行请求

image-20201215002804873

发现未进行任何更改后,请求成功!


ps:日期时间参数为JDK8提供的ZonedDateTime.now(); 时区信息

image-20201215003642255

2、The Before Route Predicate Factory

所述Before路线谓词工厂有一个参数,一个datetime(其是Java ZonedDateTime)。该谓词匹配在指定之前发生的请求datetime。下面的示例配置路由前谓词:

image-20201215003828887

测试:

image-20201215003855995

因为当前时钟在指定的Before断言的后面,不满足条件,所以此路由不会进行匹配


将时钟改为

- Before=2021-01-01T00:00:00.000+08:00[Asia/Shanghai]

image-20201215004111920

正确响应到了数据

3、The Between Route Predicate Factory

Between路线谓词工厂有两个参数,datetime1并且datetime2 这是JavaZonedDateTime对象。该谓词匹配之后datetime1和之前发生的请求datetime2。该datetime2参数必须是后datetime1。以下示例配置了路由之间的谓词:

image-20201215004741040

4、The Cookie Route Predicate Factory

所述Cookie路线谓词工厂采用两个参数,该cookienameregexp(其是Java正则表达式)。该谓词匹配具有给定名称且其值与正则表达式匹配的cookie。以下示例配置cookie路由谓词工厂:

image-20201215005324388

此路由匹配具有Cookie的请求,该Cookie的名称username1234正则表达式匹配。

测试:

使用curl命令来模拟带cookie的http请求的发送

curl http://localhost:9527/payment/get/1 --cookie "username=1234"

image-20201215005624360

匹配成功


curl http://localhost:9527/payment/get/1 --cookie "username=xxbb"

image-20201215005724636

匹配失败因为cookie没有匹配成功

5、The Header Route Predicate Factory

所述Header路线谓词工厂采用两个参数,报头name和一个regexp(其是Java正则表达式)。该谓词与具有给定名称的标头匹配,该标头的值与正则表达式匹配。以下示例配置标头路由谓词:

image-20201215005916066

如果请求具有名为X-Request-Id其值与\d+正则表达式匹配的标头(即,其值为一个或多个数字),则此路由匹配。

测试

curl http://localhost:9527/payment/get/1 --cookie "username=1234" -H "X-Request-Id:123"

image-20201215010011710

因为测试请求头X-Request-Id的值全数字,所以匹配成功


curl http://localhost:9527/payment/get/1 --cookie "username=1234" -H "X-Request-Id:XXBB8888"

image-20201215010045065

因为测试请求头X-Request-Id的值不是全数字,所以匹配失败


6、The Host Route Predicate Factory

以下略

详情请参观SpringCloud Gateway官方文档

5. Route Predicate Factories

image-20201215010429039

7、The Method Route Predicate Factory

8、The Path Route Predicate Factory

9、The Query Route Predicate Factory

10、The RemoteAddr Route Predicate Factory

11、The Weight Route Predicate Factory

Filter详解

网关过滤器作用

img

当使用微服务构建整个 API 服务时,一般有许多不同的应用在运行,如上图所示的mst-user-servicemst-good-servicemst-order-service,这些服务都需要对客户端的请求的进行 Authentication。最简单粗暴的方法就是像上图一样,为每个微服务应用都实现一套用于校验的过滤器或拦截器。

通过前置的网关服务来完成这些非业务性质的校验。

img

Filter的生命周期

Spring Cloud Gateway 的 Filter 的生命周期有两个:“pre” 和 “post”。

img

“pre”和 “post” 分别会在请求被执行前调用和被执行后调用。

Filter的种类

GatewayFilter

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway包括许多内置的GatewayFilter工厂。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QVKpDEjT-1607968987014)(https://gitee.com/huanglejia/img-typora-repo/raw/master/img/292888-20181014153300479-2003065964.png)]

GatewayFilter工厂

GlobalFilter

GlobalFilter接口具有相同的签名GatewayFilter。这些是特殊过滤器,有条件地应用于所有路由。

img

Global Filters

常用的GatewayFilter Factory

1、AddRequestHeader GatewayFilter工厂

此清单将X-Request-red:blue标头添加到所有匹配请求的下游请求的标头中。

image-20201215013801205

- AddRequestHeader=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名为X-Request-Id,值为1024

2、AddRequestParameter GatewayFilter工厂

AddRequestParameter了解用于匹配路径或主机的URI变量。URI变量可以在值中使用,并在运行时扩展。以下示例配置了AddRequestParameter GatewayFilter使用变量的:

image-20201215012526347

这将添加red=blue到所有匹配请求的下游请求的查询字符串中。

AddRequestParameter了解用于匹配路径或主机的URI变量。URI变量可以在值中使用,并在运行时扩展。

3、其他

image-20201215013907699

image-20201215013917790

更多参考官网:

GatewayFilter工厂

Global Filters

image-20201215015531072

自定义过滤器

自定义GlobalFilter的作用

全局日志记录

统一网关鉴权

自定义过滤器案例

package com.lejia.springcloud.filter;

新建MyLogGatewayFilter配置类

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

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info("***********com in MyLogGatewayFilter " + new DateTime());

        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;
    }
}

测试

http://localhost:9527/payment/lb

image-20201215015052521

image-20201215014653592

测试没有添加请求参数uname,请求在后台被Gateway给拦截住了,并返回指定的code status给前台


http://localhost:9527/payment/lb?uname=zhangsan

image-20201215015138355

当添加请求参数后,页面正常返回

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值