Spring Cloud Gateway

什么是API网关

API网关是随微服务概念兴起的一种架构模式,位于底层微服务与客户端的中间层,用于针对客户端的请求进行转发、安全认证、鉴权、监控、流控、负载均衡等通用功能。

概述

在微服务架构下,原所有功能都在单一代码库下,变为各个独立的微服务项目;随之带来的问题如:1.原有在单一代码库下做一次安全认证即可,现拆分成微服务后请求每个服务都需做一次安全验证,导致成本过高,每新增一个服务都需做一套重复的安全验证;2.拆分为微服务后,多个微服务客户端如何合理的调用?3.针对一些跨域请求,是否需每个服务都需额外处理呢?
针对以上难题,微服务引入了API网关的概念,API网关为微服务提供了统一的路由管理,作为系统的统一入口,为客户端或内部服务做中转,并能在网关层实现通用的业务逻辑、如安全认证、鉴权、路由转发、安全策略、接口防刷、监控日志等。

image

Spring Cloud Gateway是什么

Spring Cloud Gateway是基于Spring官方推出的第二代网关框架,定位取代Netflix zulu;Spring Cloud Gateway是基于Fliter的方式(责任链模式)进行提供网关基本功能;它是由WebFulx + Netty + Reactor实现的响应式(观察者模式)API网关,故此他不能在传统的servlet中工作,也不能构成war包。

Spring Cloud Gateway

核心概念

路由

路由是将请求映射到特定地址的功能,是网关最基础的部分,路由包含一个ID、目的的URL、一组断言工厂、一组Filter组成

过滤器

在Spring Cloud Gateway中Filter分为Gateway Filter和Global Filter,针对请求及响应的一些处理。

断言

断言是用于匹配请求的条件,它是路由规则的一部分,如果断言为真,则说明请求的URL和配置的路由匹配,可继续后续操作执行。

负载均衡

针对服务多个实例时,通过负载均衡算法,使流量均匀分布至每个服务。

工作原理

spring_cloud_gateway_diagram.png
客户端发起请求,如请求和路由匹配,该请求会被发送到网关特定的Web处理程序,由特定的处理程序执行请求过滤链。
在过滤链中间虚线分割代表:会在发送后端服务前后进行执行不同的过滤器,具体区分为pre过滤器及post过滤器,pre过滤器一般用于在请求后端前的一些请求参数、请求头的一些校验;post过滤器是在请求后端服务响应后对响应结果的处理过滤器。

小试牛刀

如何接入Spring Cloud Gateway

引入依赖

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

<!-- nacos服务注册与发现 -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- 3.x 版本中去除了原有的 LoadBalancer 相关的代码和类,交由loadbalancer实现,变了成了可拔插的插件 故此需单独引入 -->
<!-- 负载均衡 -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

编写YAML文件

server:
  port: 8888
spring:
  application:
    name: share-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.1.101:8848
        namespace: zyl
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order-api  #路由ID,全局唯一,建议配置服务名
          uri: lb://share-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order-api/**   # 断言,路径相匹配的进行路由
          filters:
            - StripPrefix=1
        - id: user-api   #路由ID,全局唯一,建议配置服务名
          uri: lb://share-user  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/user-api/**   # 断言,路径相匹配的进行路由
          filters:
            - StripPrefix=1

路由断言工厂配置

路由断言,判断请求是否符合要求,符合则转发到路由目的地。application.yml配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件。

路径匹配

spring:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order-api  #路由ID,全局唯一,建议配置服务名
          uri: lb://share-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order-api/**   # 断言,路径相匹配的进行路由
          filters:
            - StripPrefix=1

Header匹配

spring:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order-api  #路由ID,全局唯一,建议配置服务名
          uri: lb://share-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order-api/**   # 断言,路径相匹配的进行路由
            - Header=X-Request-Id, \d+
          filters:
            - StripPrefix=1

过滤器工厂配置

GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理

添加请求头

spring:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order-api  #路由ID,全局唯一,建议配置服务名
          uri: lb://share-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order-api/**   # 断言,路径相匹配的进行路由
          #配置过滤器工厂
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-color, red  #添加请求头

自定义过滤器工厂

spring:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order-api  #路由ID,全局唯一,建议配置服务名
          uri: lb://share-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order-api/**   # 断言,路径相匹配的进行路由
          #配置过滤器工厂
          filters:
            - StripPrefix=1
            - CheckAuth=auth, zyl

全局过滤器配置

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。
GatewayFilter:网关过滤器,需要通过spring.cloud.routes.filters配置在具体的路由下,只作用在当前特定路由上,也可以通过配置spring.cloud.default-filters让它作用于全局路由上。
GlobalFilter:全局过滤器,不需要再配置文件中配置,作用在所有的路由上,最终通过 GatewayFilterAdapter包装成GatewayFilterChain能够识别的过滤器。

LoadBalancerClientFilter

spring:
    gateway:
      #设置路由:路由id、路由到微服务的uri、断言
      routes:
        - id: order-api  #路由ID,全局唯一,建议配置服务名
          uri: lb://share-order  #lb 整合负载均衡器ribbon,loadbalancer
          predicates:
            - Path=/order-api/**   # 断言,路径相匹配的进行路由
          #配置过滤器工厂
          filters:
            - StripPrefix=1

自定义全局过滤器

自定义全局过滤器定义方式是实现GlobalFilter接口。每一个过滤器都必须指定一个int类型的order 值,order值越小,过滤器优先级越高,执行顺序越靠前。GlobalFilter通过实现Ordered接口来指定order值


/**
 * 每一个过滤器都必须指定一个int类型的order值,order值越小,过滤器优先级越高,执行顺序越靠前。
 * GlobalFilter通过实现Ordered接口,来指定order值
 */
@Slf4j
@Component
public class CheckAuthFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取token
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if (null == token) {
            log.info("token is null");
            ServerHttpResponse response = exchange.getResponse();
            response.getHeaders().add("Content-Type",
                    "application/json;charset=UTF-8");
            // 401 用户没有访问权限
            response.setStatusCode(UNAUTHORIZED);
            byte[] bytes = UNAUTHORIZED.getReasonPhrase().getBytes();
            DataBuffer buffer = response.bufferFactory().wrap(bytes);
            // 请求结束,不继续向下请求
            return response.writeWith(Mono.just(buffer));
        }

        // TODO 校验token进行身份认证

        log.info("校验token");
        return chain.filter(exchange);
    }

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

跨域配置

在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。
同源策略(Same Orgin Policy)是一种约定,它是浏览器核心也最基本的安全功能,它会阻止一个域的js脚 本和另外一个域的内容进行交互,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源 (即在同一个域)就是两个页面具有相同的协议(protocol)、主机(host)和端口号(port)。
截屏2023-03-30 22.12.58.png

YAML配置

spring:
  	gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION

JAVA配置

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}
posted @ 2023-03-30 22:26  雨伦  阅读(90)  评论(0)    收藏  举报