SpringCloud Gateway网关

SpringCloud Gateway网关

05、Gateway:网关介绍

官网学习地址:https://spring.io/projects/spring-cloud-gateway#learn

Spring Cloud Gateway简介

  • Gateway基于Spring 5.0+、Spring Boot 2.0+、WebFlux、Netty等技术开发的网关服务。
  • Gateway基于Filter链提供网关基本功能:断言、路由、过滤、限流等。
  • Gateway为微服务架构提供简单、有效、统一的API路由管理方式。
  • Gateway是替代Netflix公司Zuul的一套解决方案。

Gateway组件的核心是一系列的过滤器,通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前面的防火墙和代理器,隐藏微服务节点IP与端口信息,从而达到保护微服务的目的。Spring Cloud Gateway本身也是一个微服务,且必须连接到Eureka服务注册中心,因为需要拉取服务列表,才能做转发请求。

Gateway加入后的架构

在这里插入图片描述
说明:不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都可经过网关,然后再由网关来实现鉴权、动态路由等等操作。Gateway就是我们微服务调用的统一入口。

核心概念

  • 路由(route):由一个ID、一个目标URI、一组断言工厂、一组过滤器组成。如果断言为真,该请求就会 路由到 目标URI。

  • 断言(Predicate):用断言工厂去匹配请求URL。如果能匹配,断言为真。

  • 过滤器(Filter):用过滤器过滤请求,例如过滤请求URL、过滤请求参数、过滤请求头等。

06、Gateway:快速入门

6.1 创建模块

  • 填写基本信息

在这里插入图片描述
在这里插入图片描述

  • 添加依赖
  • <?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">
        <parent>
            <artifactId>springcloud-demo</artifactId>
            <groupId>cn.itcast</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
        <artifactId>gateway-server</artifactId>
    
        <dependencies>
            <!-- 配置eureka客户端启动器 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!-- 配置gateway启动器(基于netty运行,所在不需要tomcat启动器) -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
        </dependencies>
    </project>
    

6.2 编写启动类

在gateway-server中创建cn.itcast.GatewayApplication启动类

package cn.itcast;

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

6.3 编写配置

在gateway-server中创建application.yml文件,内容如下:

server:
  port: 10010
spring:
  application:
    name: api-gateway

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka

注意:必须设置拉取服务为true(默认也是为true),因为需要转发请求到具体服务,或者使用默认值

6.4 编写路由规则

  • 启动三个Spring Boot应用:
    在这里插入图片描述
  • 需要用网关来代理user-service服务,先看一下控制面板中的服务状态:
    在这里插入图片描述
  • 修改gateway-server的application.yml文件:

    server:
      port: 10010
    spring:
      application:
        name: api-gateway
      cloud:
        gateway:
          routes:
            # 路由id, 路由信息的唯一标识, 可以随意写
            - id: user-service-route
              # 路由的目标服务地址
              uri: http://127.0.0.1:9001
              # 断言,Path: 匹配路由映射路径
              predicates:
                - Path=/**
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
    
    • 将符合 Path 规则的一切请求,都代理或路由到 uri 参数指定的地址
    • 本例中,我们将路径中包含有 /** 开头的请求,代理到http://127.0.0.1:9001

6.5 启动测试

访问的路径中需要加上配置规则的映射路径,我们访问:http://localhost:10010/user/1
在这里插入图片描述

07、Gateway:面向服务路由

在刚才的路由规则中,把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然不合理。 应该根据服务的id,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由!

  • 修改映射配置,通过服务名称获取

    因为已经配置了Eureka客户端,可以从Eureka获取服务的地址信息。修改application.yml文件:

    server:
      port: 10010
    spring:
      application:
        name: api-gateway
      cloud:
        gateway:
          routes:
            # 路由id,可以随意写
            - id: user-service-route
              # 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
              # loadBalance
              uri: lb://user-service
              # 断言,Path: 配置路由映射路径
              predicates:
                - Path=/**
    
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
    

    路由配置中uri所用的协议为lb时(以uri: lb://user-service为例),gateway将使用 LoadBalancerClient把user-service通过eureka解析为实际的主机和端口,并进行ribbon负载均衡。
    在这里插入图片描述
    启动测试

再次启动,这次gateway进行代理时,会利用Ribbon进行负载均衡访问:
在这里插入图片描述

  • 说明: spring-cloud-gateway网关服务,默认就已经集成了Ribbon负载均衡(轮询算法)

08、Gateway:路由前缀

8.1 添加前缀

在gateway中可以通过配置网关过滤器PrefixPath,实现映射路径中的地址添加前缀,修改application.yml文件:

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        # 路由id,可以随意写
        - id: user-service-route
          # 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
          uri: lb://user-service
          # 断言,配置路由映射路径
          predicates:
            - Path=/**
          filters:
            # 添加前缀: 指定路由路径需要添加的前缀
            - PrefixPath=/user

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka

通过 PrefixPath=/xxx 来指定了路由要添加的前缀。

  • PrefixPath=/user,转换效果: http://localhost:10010/1 => http://localhost:9001/user/1

  • PrefixPath=/user/abc,转换效果: http://localhost:10010/1 => http://localhost:9001/user/abc/1 以此类推。

在这里插入图片描述

8.2 去除前缀

在gateway中可以通过配置网关过滤器StripPrefix,实现映射路径中的地址去除前缀,修改application.yml文件:

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        # 路由id,可以随意写
        - id: user-service-route
          # 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
          uri: lb://user-service
          # 断言,Path: 配置路由映射路径
          predicates:
            - Path=/**
          filters:
            # 去除前缀: 1去除一个前缀,2去除两个前缀,以此类推
            - StripPrefix=1

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka

通过 StripPrefix=1 来指定了路由要去掉的前缀个数。如:路径 /api/user/1 将会被代理到 /user/1。

  • StripPrefix=1,转换效果: http://localhost:10010/api/user/1 => http://localhost:9001/user/1
  • StripPrefix=2,转换效果:http://localhost:10010/api/user/1 => http://localhost:9001/1

以此类推。
在这里插入图片描述

作用:通过路由前缀可区分微服务,且可以对用户隐藏服务真实url

09、Gateway:过滤器介绍

过滤器简介

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

  • Gateway自带过滤器有30多个,常见自带过滤器有:

    过滤器名称 说明
    AddRequestHeader 对匹配上的请求添加Header
    AddRequestParameters 对匹配上的请求添加参数
    AddResponseHeader 对从网关返回的响应添加Header
    StripPrefix 对匹配上的请求路径去除前缀

在这里插入图片描述

  • 详细的说明在: 官网链接

  • 过滤器类型:

    • 全局过滤器:自定义全局过滤器,需实现 GlobalFilter、Ordered两个接口。不需要在配置文件中配置,作用在所有的路由上。
    • 局部过滤器:通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上,自带的30几个过滤器都可以配置。

过滤器执行生命周期

Spring Cloud Gateway 的 Filter 的生命周期有两个(前置过滤与后置过滤):“pre” 和 “post”,分别会在请求执行前调用 或 请求执行后调用。
在这里插入图片描述
过滤器使用场景(例举):

  • 请求鉴权:判断用户是否登录,是否对某接口有权限等(前置过滤)
  • 服务调用时长统计:在请求执行前记录时间,在请求执行后计算该服务的调用时间(后置过滤)。

10、Gateway:配置默认过滤器

我们可以将Spring Cloud Gateway自带的过滤器配置成默认过滤器: 不是针对一个路由;而是对全部路由有效。(相当于全局过滤器)

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      # 默认过滤器,对全部路由有效
      default-filters:
        # 添加响应头过滤器,添中一个响应头为name,值为admin
        - AddResponseHeader=name,admin
      routes:
        # 路由id,可以随意写
        - id: user-service-route
          # 代理的服务地址;lb表示负载均衡(从eureka中根据服务id获取服务实例)
          uri: lb://user-service
          # 断言,Path: 配置路由映射路径
          predicates:
            - Path=/api/user/**
          filters:
            # 去除前缀: 1去除一个前缀,2去除两个前缀,以此类推
            - StripPrefix=1

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka

运行测试:
在这里插入图片描述

11、Gateway:自定义全局过滤器

需求:模拟一个登录的校验。基本逻辑:如果请求中有token参数,则认为请求有效,放行。

  • 在gateway-server模块中编写全局过滤器: MyGlobalFilter

    package cn.itcast.filter;
    
    import org.apache.commons.lang.StringUtils;
    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;
    
    /** 自定义全局过滤器 */
    @Component
    public class MyGlobalFilter implements GlobalFilter, Ordered {
          
          
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
          
          
            System.out.println("==全局过滤器MyGlobalFilter==");
            String token = exchange.getRequest().getQueryParams().getFirst("token");
            if (StringUtils.isBlank(token)){
          
          
                // 设置响应状态码: 401 未授权
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                // 返回响应完成
                return exchange.getResponse().setComplete();
            }
            // 放行,让其它的过滤器继续执行
            return chain.filter(exchange);
        }
        @Override
        public int getOrder() {
          
          
            // 值越小越先执行
            return 1;
        }
    }
    
  • 测试访问

    • 访问 http://localhost:10010/api/user/1,页面提示401

    • 访问 http://localhost:10010/api/user/1?token=abc
      在这里插入图片描述

12、Gateway:集成Hystrix

目标: spring-cloud-gateway集成Hystrix实现线程隔离。

  • 第一步:在gateway-server中,添加hystrix启动器

    <!-- 配置hystrix启动器 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  • 第二步:配置线程隔离时间

    # 线程隔离
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 1000
    
  • 第三步:在默认过滤器中配置Hystrix过滤器(对全部路由有效)

    spring:
      cloud:
        gateway:
          # 配置默认过滤器(对全部路由有效)
          default-filters:
          # 添加响应头,响应头的名称为name 值为admin
          - AddResponseHeader=name,admin
          - name: Hystrix  # 配置Hystrix过滤器
            args:          # 配置两个参数
              name: fallbackcmd
              fallbackUri: forward:/fallback
    
  • 第四步:创建FallbackController.java控制器,提供服务降级方法

    package cn.itcast.controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class FallbackController {
          
          
        @GetMapping("/fallback")
        public String fallback(){
          
          
            return "您好,服务器正忙,请稍候再试。。。";
        }
    }
    
  • 第五步:测试

    在这里插入图片描述

13、Gateway:高可用

  • 启动多个Gateway服务,自动注册到Eureka,就可以形成集群。

    • Gateway被内部微服务访问,自动负载均衡(Ribbon)。

    • Gateway被外部访问,如PC端、移动端等。它们无法通过Ribbon进行负载均衡,那么该怎么办?

      此时,可以使用其它的服务网关,来对Gateway做负载均衡。比如:【Nginx、Apache、F5】

  • Gateway与Feign的区别

    • Gateway 作为整个应用的入口,接收所有的请求,如PC、移动端等,并且将不同的请求路由至不同的微服务,大部分情况下用作权限鉴定、流量控制。
    • Feign 主要用于微服务与微服务之间的调用。

Memorial Day is 514 days
I miss you
xiaokeai

猜你喜欢

转载自blog.csdn.net/weixin_42914989/article/details/114117559