SpringCloud学习九(SpringCloud微服务之网关Gateway)

一、SpringCloud Gateway简介

Gateway网关是我们服务的守门神,所有前端访问微服务的统一入口,旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。

核心功能特性:

  • 请求路由
  • 集成 Hystrix 断路器
  • 权限控制
  • 限流

加入网关后的服务结构:在这里插入图片描述

路由:gateway加入后,一切请求都必须先经过gateway,因此gateway就必须根据某种规则,把请求转发到某个微服务,这个过程叫做路由。

  • 路由基本组成
    id:路由的唯一标识
    uri:路由的目的地
    predicates:断言:是否满足此路由的条件
    filters:过滤器

权限控制:请求经过路由时,我们可以判断请求者是否有请求资格,如果没有则进行拦截。

限流:当请求流量过高时,在网关中按照下流的微服务能够接受的速度来放行请求,避免服务压力过大。

网关的实质:网关中的每一个功能都是由过滤器链完成的。

gateway网关的优点:

  • 安全 ,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
  • 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
  • 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
  • 减少了客户端与各个微服务之间的交互次数
  • 易于统一授权。

二、gateway快速入门

(1)、引入依赖

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

(2)、编写启动类

@SpringBootApplication
public class GatewayApplication {

	public static void main(String[] args) {
		SpringApplication.run(GatewayApplication.class, args);
	}
}

3、编写配置(application.yml文件中)

server:
  port: 10010 #服务端口
spring: 
  application:  
    name: gateway-server #指定服务名

映射规则:

server:
  port: 10010 #服务端口
spring:
  application:
    name: gateway-server #指定服务名
  cloud:
    gateway:
      routes:
        - id: user-service # 当前路由的唯一标识
          uri: http://127.0.0.1:8081 # 路由的目标微服务地址
          predicates: # 断言  判断 前端浏览器发送url和当前path是否匹配
            - Path=/user/** # 按照路径匹配的规则
#        - id: order-service # 当前路由的唯一标识
#          uri: http://127.0.0.1:9081 # 路由的目标微服务地址
#          predicates: # 断言  判断 前端浏览器发送url和当前path是否匹配
#            - Path=/order/** # 按照路径匹配的规则

三、面向服务的路由

(1)、添加依赖

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

(2)、添加Eureka配置

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

(3)、修改映射配置

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
spring:
  cloud:
    gateway:
      routes:
          # id:路由的唯一标识
        - id: user-service-route
          # uri:如果满足路由规则要跳转的路径
          uri: lb://user-service   # lb:(load balance)负载均衡(默认轮询)   user-service:服务的名称
          # predicates:断言 是否满足路由的条件
          predicates:
            - Path=/user-api/**  # 请求路径:http://127.0.0.1:10010/user/aaa满足/user/**规则,将访问
        - id: consumer-service-route
          uri: lb://consumer-service
          predicates:
            - Path=/consumer/**

四、其他路由方式(可以在官网查看)

  • After Route Predicate Factory、Before Route Predicate Factory和Between Route Predicate Factory:基于请求时间的路由规则
  • Cookie Route Predicate Factory:基于cookie值的路由匹配规则
  • Header Route Predicate Factory:基于请求头的路由匹配规则
  • Host Route Predicate Factory:基于主机名的路由匹配规则
  • Method Route Predicate Factory:基于请求方式的路由匹配规则
  • Path Route Predicate Factory:基于请求路径的路由匹配规则
  • Query Route Predicate Factory:基于请求参数的路由匹配规则
  • RemoteAddr Route Predicate Factory:基于请求者ip地址的路由匹配规则

五、局部过滤器

GatewayFilter Factories是Gateway中的局部过滤器工厂,作用于某个特定路由,允许以某种方式修改传入的HTTP请求或返回的HTTP响应。

  1. 局部过滤器,配置到哪个路由下,会对满足该路由的请求和响应生效
  2. gateway内置了很多局部过滤器,可以直接配置使用
  3. 可以通过 default-filters配置默认过滤器,对全部路由失效

1、添加请求头

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
spring:
  cloud:
    gateway:
      routes:
          # id:路由的唯一标识
        - id: user-service-route
          # uri:如果满足路由规则要跳转的路径
          uri: lb://user-service   # lb:(load balance)负载均衡(默认轮询)   user-service:服务的名称
          # predicates:断言 是否满足路由的条件
          predicates:
            - Path=/user-api/**  # 请求路径:http://127.0.0.1:10010/user/aaa满足/user/**规则,将访问
          # filter:过滤器
          # - filters:就是当前路由规则的所有过滤器配置
          # AddRequestHeader是添加一个头信息
          filters:
            - AddRequestHeader=name,rrx  # 添加请求头过滤器 在请求头中添加 key:name value:rrx

2、Hystrix支持

网关做请求路由转发,如果被调用的请求阻塞,需要通过Hystrix来做线程隔离和熔断,防止出现故障。

(1)、引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
(2)、定义降级的处理函数
@RestController
public class FallbackController {

    @RequestMapping(value = "/fallbackTest")
    public Map<String, String> fallBackController() {
        Map<String, String> response = new HashMap<>();
        response.put("code", "502");
        response.put("msg", "服务超时");
        return response;
    }
(3)、定义降级处理规则
spring:
  cloud:
    gateway:
      routes:
          # id:路由的唯一标识
        - id: user-service-route
          # uri:如果满足路由规则要跳转的路径
          uri: lb://user-service   # lb:(load balance)负载均衡(默认轮询)   user-service:服务的名称
          # predicates:断言 是否满足路由的条件
          predicates:
            - Path=/user-api/**  # 请求路径:http://127.0.0.1:10010/user/aaa满足/user/**规则,将访问
          # filter:过滤器
          # - filters:就是当前路由规则的所有过滤器配置
          # AddRequestHeader是添加一个头信息
          filters:
            - AddRequestHeader=name,rrx  # 添加请求头过滤器 在请求头中添加 key:name value:rrx
     default-filters:
        - name: Hystrix # 指定过滤工厂名称
          args: # 指定过滤的参数
            name: fallbackcmd  # hystrix的指令名
            fallbackUri: forward:/fallbackTest # 失败后的跳转路径
hystrix:
  command:
    default:
      execution.isolation.thread.timeoutInMilliseconds: 1000 # 失败超时时长
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

3、路由前缀(去除路由前缀)

  # filter:过滤器
          filters:
            - AddRequestHeader=name,rrx  # 添加请求头过滤器 在请求头中添加 key:name value:rrx
            - StripPrefix=1  # 忽略几级路径  如:/user-api/user/aaa== 》/user/aaa

六、全局过滤器

全局过滤器Global Filter 与局部的GatewayFilter会在运行时合并到一个过滤器链中,并且根据org.springframework.core.Ordered来排序后执行,顺序可以通过getOrder()方法或者@Order注解来指定。

1、GlobalFilter接口

public interface GlobalFilter {

	/**
	 * Process the Web request and (optionally) delegate to the next {@code WebFilter}
	 * through the given {@link GatewayFilterChain}.
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

}

参数:exchange 对请求和响应进行了封装
参数:chain 过滤器链,gateway中可以有多个过滤器

2、过滤器顺序

优先级最高的过滤器,会在pre过程的第一个执行,在post过程的最后一个执行在这里插入图片描述

七、自定义全局过滤器

@Component
@Order(-1) //越小越优先
public class LoginFilter implements GlobalFilter { //, Ordered

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1 得到 request 对象
        ServerHttpRequest request = exchange.getRequest();

        // 2 从request获取请求参数 access-token
        String token = request.getQueryParams().getFirst("access-token");

        // 3 判断access-token值是否为admin
        if (!"admin".equals(token)) {  // 拦截
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 放行
        return chain.filter(exchange);
    }

    // 越小越优先
//    @Override
//    public int getOrder() {
//        return -1;
//    }
}

2、 多过滤器演示

@Slf4j
@Configuration
public class FilterConfiguration {

    @Bean
    @Order(-2)
    public GlobalFilter globalFilter1(){
        return ((exchange, chain) -> {
            log.info("过滤器1的pre阶段!");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("过滤器1的post阶段!");
            }));
        });
    }

    @Bean
    @Order(-1)
    public GlobalFilter globalFilter2(){
        return ((exchange, chain) -> {
            log.info("过滤器2的pre阶段!");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("过滤器2的post阶段!");
            }));
        });
    }

    @Bean
    @Order(0)
    public GlobalFilter globalFilter3(){
        return ((exchange, chain) -> {
            log.info("过滤器3的pre阶段!");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("过滤器3的post阶段!");
            }));
        });
    }
}

在这里插入图片描述

八、网关限流

在这里插入图片描述
常见算法:

  • 计数器算法
  • 漏桶算法
  • 令牌桶算法
    算法介绍参考:
    https://blog.csdn.net/u012441595/article/details/102483501

1、令牌桶算法原理

  • 准备一个令牌桶,有固定容量,一般为服务并发上限
  • 按照固定速率,生成令牌并存入令牌桶,如果桶中令牌数达到上限,就丢弃令牌。
  • 每次请求调用需要先获取令牌,只有拿到令牌,才继续执行,否则选择选择等待或者直接拒绝。
    在这里插入图片描述

2、Gateway中限流实现

(1)、引入依赖
<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
(2)、在application.yml中配置Redis地址:
spring:
  redis:
    host: 192.168.200.129
(3)、配置过滤条件key
  • 给不同的请求URI路径设置不同令牌桶
return Mono.just(exchange.getRequest().getURI().getPath());// 获取请求URI
  • 给不同的登录用户设置不同令牌桶
return exchange.getPrincipal().map(Principal::getName);// 获取用户
  • 给不同的请求IP地址设置不同令牌桶
return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());// 获取请求者IP

配置一个KeyResolver的Bean实例:

@Component
public class IpKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }
}

配置桶参数

server:
  port: 10010
spring:
  application:
    name: gateway-server
  redis:
    host: 192.168.200.150
  # 路由规则
  cloud:
    gateway:
      routes:
          # id:路由的唯一标识
        - id: user-service-route
          # uri:如果满足路由规则要跳转的路径
          uri: lb://user-service   # lb:(load balance)负载均衡(默认轮询)   user-service:服务的名称
          # predicates:断言 是否满足路由的条件
          predicates:
            - Path=/user-api/**  # 请求路径:http://127.0.0.1:10010/user/aaa满足/user/**规则,将访问
          # filter:过滤器
          filters:
            - AddRequestHeader=name,rrx  # 添加请求头过滤器 在请求头中添加 key:name value:rrx
            - StripPrefix=1  # 忽略几级路径  如:/user-api/user/aaa== 》/user/aaa
        - id: consumer-service-route
          uri: lb://consumer-service
          predicates:
            - Path=/consumer/**
      default-filters:
        - name: Hystrix # 指定过滤工厂名称
          args: # 指定过滤的参数
            name: fallbackcmd  # hystrix的指令名
            fallbackUri: forward:/fallbackTest # 失败后的跳转路径
        - name: RequestRateLimiter #请求数限流 名字不能随便写
          args:
            key-resolver: "#{@ipKeyResolver}" # 指定一个key生成器
            redis-rate-limiter.replenishRate: 2 # 生成令牌的速率
            redis-rate-limiter.burstCapacity: 5 # 桶的容量
eureka:
  client:
    service-url:
      defaultZone: http://localhost:10086/eureka
  • key-resolver:"#{@ipKeyResolver}"是SpEL表达式,写法是#{@bean的名称},ipKeyResolver就是我们定义的Bean名称
  • redis-rate-limiter.replenishRate:每秒钟生成令牌的速率
  • redis-rate-limiter.burstCapacity:令牌桶的容量

九、跨域配置

跨域:浏览器的同源策略。网络通信的三要素:IP、PORT、协议,只要是三要素中的一个不相同,则会触发浏览器同源策略,出现跨域现象。

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': # 匹配所有请求
              allowedOrigins: "*" #跨域处理 允许所有的域
              allowedMethods: # 支持的方法
                - GET
                - POST
                - PUT
                - DELETE
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页