SpringCloud:网关Gateway

SpringCloud:网关Gateway,第1张

SpringCloud:网关Gateway

目录

一、前言

二、Gateway介绍

1.什么是SpringCloud Gateway

2.SpringCloud Gateway功能特征

3.核心概念

   路由 (route)

   断言 (predicates)

   过滤器(filter)

三、SpringCloudGateway快速开始

四、SpringCloudGatewat整合Nacos

五、路由断言工厂(Route Predicate Factories)

1.内置断言工厂

基于Datetime类型的断言工厂

基于远程地址的断言工厂

基于cookie的断言工厂

基于Header的断言工厂

基于Host的断言工厂

基于Method的断言工厂

基于Path请求路径的断言工厂

基于Query请求参数的断言工厂

基于路由权重的断言工厂

2.自定义路由断言工厂

六、过滤器工厂(Gateway Filter Factories)

1.内置过滤器工厂

AddRequestHeader

 AddRequestParameter

 AddResponseHeader

DedupeResponseHeader

2.自定义过滤器工厂

3.全局过滤器(Global Filters)

1.内置全局过滤器

2.自定义全局过滤器

七、Reactor Netty访问日志

八、Gateway跨域设置

九、Gateway整合Sentinel流控降级


一、前言

所谓API网关,就是指系统的统一入口,它封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,比如:认证、鉴权、监控、路由转发等。

利用API网关可以解决以下问题:

全局性流控日志统计防止sql注入防止web攻击屏蔽工具扫描黑白ip名单证书/加解密处理服务级别流控服务降级与熔断路由与负载均衡、灰度策略服务过滤、聚合与发现权限验证与用户等级策略业务规则与参数检验多级缓存策略


二、Gateway介绍 1.什么是SpringCloud Gateway

网关作为流量的入口,常用的功能包括路由转发、权限检验、限流等。

SpringCloud Gateway是SpringCloud官方推出的第二代网关框架。相比Zuul来说,SpringCloudGateway提供更优秀的性能,更强大的功能。

SpringCloud Gateway是由WebFlux + Netty +Reactor 实现的响应式的API网关。它不能在传统的servlet容器中工作,也不能构建成war包。

SpringCloudGateway旨在微服务架构提供一种简单且有效的API路由的管理方式,并基于Filter的方式提供网关的基本功能,例如说安全认证,监控、限流等等。

官方文档:Spring Cloud Gateway

2.SpringCloud Gateway功能特征

基于Spring framework5、ProjectReactor和SpringBoot2.0进行构建动态路由,能够匹配任何请求属性支持路径重写集成SpringCloud服务发现功能可以集成流控降级功能可以对路由指定易于编写的Predicate(断言)和Filter(过滤器) 3.核心概念    路由 (route)

    路由是网关中最基础的部分,路由信息包括一个ID、一个目的uri、一组断言工厂、一组filter组成。如果断言为真,则说明请求的url和配置的路由匹配。      

   断言 (predicates)

    Java8中的断言函数,SpringCloudGateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义匹配 HttpRequest中的任何信息,比如请求头和参数等。

   过滤器(filter)

    SpringCloudGateway中的filter分为Gateway Filter 和Global Filter。Filter可以对请求和响应进行处理。


三、SpringCloudGateway快速开始

1.导入依赖

        
            org.springframework.cloud
            spring-cloud-starter-gateway
        

2.编写yml配置文件

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    #网关配置
    gateway:
      #路由规则配置
      routes:
          - id: order_route  #路由的唯一标识,路由到订单服务
            uri: http://localhost:8010   #需要转发的地址
            predicates:
                  - Path=/order-service/**
                  #将http://localhost:8088/order-service/order/add请求路由到↓
                  #http://localhost:8010/order-service/order/add
            filters:
                  - StripPrefix=1  #StripPrefix内置过滤器中的一种,转发去掉之前第一层路径,把http://localhost:8010/order-service/order/add 变成 http://localhost:8010/order/add


3.这就简单实现了


四、SpringCloudGatewat整合Nacos

 在上述中,我们在配置文件中写死了转发路径的地址,接下来我们从注册中心获取此地址。

 1.引入依赖

 
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        

 2.编写yml配置文件

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    #网关配置
    gateway:
      #路由规则配置
      routes:
          - id: order_route  #路由的唯一标识,路由到订单服务
            uri: lb://order-service   #需要转发的地址  lb: 使用nacos中的本地负载均衡策略  order-service:服务名
            predicates:
                  - Path=/order-service/**
                  #将http://localhost:8088/order-service/order/add请求路由到↓
                  #http://localhost:8010/order-service/order/add
            filters:
                  - StripPrefix=1  #StripPrefix内置过滤器中的一种,转发去掉之前第一层路径,把http://localhost:8010/order-service/order/add 变成 http://localhost:8010/order/add
    # Nacos配置
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

简写: 去掉关于路由的配置,自动寻找服务。

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    #网关配置
    gateway:
      discovery:
        locator:
          enabled: true #是否启动自动识别nacos服务
    # Nacos配置
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

这种方式在实际开发中是不常用的,大家知道即可。

这里就完成了与nacos的整合。


五、路由断言工厂(Route Predicate Factories)

作用:当请求gateway的时候,使用断言对请求进行匹配,如果匹配成功,就进行路由转发,如果匹配失败就返回404。

1.内置断言工厂

SpringCloudGateway包括许多内置的断言工厂,所有这些断言都与http请求的不同属性匹配。

基于Datetime类型的断言工厂

此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory:接收一个日期参数,判断请求日期是否晚于指定日期。

BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期。

BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内。

- After=2022-01-29T15:49:47.789+08:00[Asia/Shanghai]

- Before=2022-01-29T15:49:47.789+08:00[Asia/Shanghai]

- Between=2022-01-29T15:49:47.789+08:00[Asia/Shanghai], 2022-01-30T15:49:47.789+08:00[Asia/Shanghai]
基于远程地址的断言工厂

RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中。

- RemoteAddr=192.168.1.1/24
基于cookie的断言工厂

cookieRoutePredicateFactory: 接收两个参数,cookie名字和一个正则表达式。判断请求cookie是否具有给定名称且值与正则表达式匹配。

- cookie=chocolate, ch.p
基于Header的断言工厂

HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。判断请求Header是否具有给定名称且值与正则表达式匹配 。

- Header=X-Request-Id, d+
基于Host的断言工厂

HostRoutePredicateFactory: 接收一个参数,主机名模式。判断请求的host是否满足匹配规则。

- Host=**.somehost.org,**.anotherhost.org
基于Method的断言工厂

MethodRoutePredicateFactory: 接收一个参数,判断请求类型是否跟指定的类型匹配。

- Method=GET,POST
基于Path请求路径的断言工厂

PathRoutePredicateFactory: 接收一个参数,判断请求的uri部分是否满足路径规则。

- Path=/red/{segment},/blue/{segment}
基于Query请求参数的断言工厂

QueryRoutePredicateFactory:接收两个参数,请求param和正则表达式,判断请求参数是否具有给定名称且值与正则表达式匹配 。

- Query=green
基于路由权重的断言工厂

WeightRoutePredicateFactory:接收一个[组名,权重],然后对于同一个组内的路由按照权重转发。

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

该路由会将约 80% 的流量转发到weightlow.org,将约 20% 的流量转发到weightlow.org。

 详细请看官方文档

2.自定义路由断言工厂

自定义路由断言工厂需要继承AbstractRoutePredicateFactory类,重写apply方法的逻辑。在apply方法中可以通过exchange.getRequest()拿到ServletHttpRequest对象,从而可以获取到请求的参数,请求方式,请求头等信息。

注:命名需以RoutePredicateFactory结尾。

package com.zjb.predicates;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

@Component
public class DiyRoutePredicateFactory extends AbstractRoutePredicateFactory{

    public static final String NAME = "name";

    public DiyRoutePredicateFactory() {
        super(DiyRoutePredicateFactory.Config.class);
    }

    @Override
    public List shortcutFieldOrder() {
        return Arrays.asList(NAME);
    }

    @Override
    public Predicate apply(DiyRoutePredicateFactory.Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                if(config.getName().equals("test")){
                    return true;
                }
                return false;
            }
        };
    }

    @Validated
    public static class Config {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}

yml配置文件中引用

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    #网关配置
    gateway:
      #路由规则配置
      routes:
          - id: order_route  #路由的唯一标识,路由到订单服务
            uri: lb://order-service   #需要转发的地址  lb: 使用nacos中的本地负载均衡策略  order-service:服务名
            predicates:
                  - Diy=name,test
    # Nacos配置
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

六、过滤器工厂(Gateway Filter Factories) 1.内置过滤器工厂

SpringCloudGateway内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理,比如添加剔除响应头 ,添加去除参数等。

AddRequestHeader

AddRequestHeader:为原始请求添加header。

 filters:
     - AddRequestHeader=X-Request-red, blue
 AddRequestParameter

AddRequestParameter:为原始请求添加请求参数。

filters:
     - AddRequestParameter=red, blue
 AddResponseHeader

AddResponseHeader:为原始响应添加header。

filters:
    - AddResponseHeader=X-Response-Red, Blue
DedupeResponseHeader

DedupeResponseHeader:剔除响应头中重复的值。

filters:
    - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

因为官方提供的内置过滤器工厂太多了,这里就不在一一列举,详细看官方文档

2.自定义过滤器工厂

自定义过滤器工厂需要继承AbstractNamevalueGatewayFilterFactory。

注:自定义名称必须要以GatewayFilterFactory结尾并交给Spring管理。

package com.zjb.filters;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;

@Component
public class DiyGatewayFilterFactory extends AbstractGatewayFilterFactory {

    public static final String NAME = "name";


    public static final String VALUE = "value";

    public DiyGatewayFilterFactory() {
        super(DiyGatewayFilterFactory.Config.class);
    }

    @Override
    public List shortcutFieldOrder() {
        return Arrays.asList(NAME,VALUE);
    }

    @Override
    public GatewayFilter apply(DiyGatewayFilterFactory.Config config) {
        return new GatewayFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange,
                                     GatewayFilterChain chain) {
                if (exchange.getRequest().getQueryParams().containsKey(NAME)) {
                    List values = exchange.getRequest().getQueryParams().get(NAME);
                    if(values.contains(config.getValue())){
                         return chain.filter(exchange);
                    }
                }
                //返回404
                exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
                return exchange.getResponse().setComplete();
            }
        };
    }

    public static class Config {

        private String name;

        private String value;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}
3.全局过滤器(Global Filters)

局部过滤器与全局过滤器的区别:

局部:局部过滤器针对某个路由,需要在路由中进行配置。

全局:全局过滤器是针对所有路由请求,一旦定义就会投入使用。

Global Filter接口和GatewayFilter有一样的接口定义,只不过,GlobalFilter会作用于所有路由。

1.内置全局过滤器

详细查看官方文档

2.自定义全局过滤器

实现GlobalFilter接口,并交给Spring管理。

使用场景:日志记录、权限认证等会使用自定义全局过滤器。

package com.zjb.filters;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class LogGlobalFilter implements GlobalFilter {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info(exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

七、Reactor Netty访问日志

要启用Reactor Netty访问日志,需要设置

-Dreactor.netty.http.server.accessLogEnabled=true

它必须是Java系统属性,而不是 Spring Boot 属性。


八、Gateway跨域设置

通过 yml方式

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':  #允许跨域访问的资源
            allowedOrigins: "*"  #跨域允许来源
            allowedMethods:  #跨域允许请求方式
            - GET
            - POST
            - PUT
            - DELETE
            - OPTION

通过java配置方式

package com.zjb.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlbasedCorsConfigurationSource;

@Configuration
public class CorsConfig {

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

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

        return new CorsWebFilter(source);
    }
}

九、Gateway整合Sentinel流控降级

网关作为内部系统外的一层屏障,对内起到一定的保护作用,限流便是其中之一,网关层的限流 可以简单针对不同路由进行限流,也可以针对业务的接口进行限流,或者根据接口的特征分组限流。

1.导入依赖

        
            com.alibaba.cloud
            spring-cloud-alibaba-sentinel-gateway
        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
        

2.添加配置

server:
  port: 8088
spring:
  application:
    name: api-gateway
  cloud:
    #网关配置
    gateway:
      #路由规则配置
      routes:
          - id: order_route  #路由的唯一标识,路由到订单服务
            uri: lb://order-service   #需要转发的地址  lb: 使用nacos中的本地负载均衡策略  order-service:服务名
            predicates:
                  - Path=/order-service/**
                  #将http://localhost:8088/order-service/order/add请求路由到↓
                  #http://localhost:8010/order-service/order/add
            filters:
                  - StripPrefix=1  #StripPrefix内置过滤器中的一种,转发去掉之前第一层路径,把http://localhost:8010/order-service/order/add 变成 http://localhost:8010/order/add
    # Nacos配置
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos

   #配置sentinel
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080

到这里就整合完毕了,网上其它的一些整合文章会去配置一些配置类,是因为使用了官方提供的Spring Cloud Gateway 的适配模块,也就是一下依赖


    com.alibaba.csp
    sentinel-spring-cloud-gateway-adapter
    x.y.z

但在2.1.6之后,我们可以直接使用sentinel和gateway的整合包来替代

        
            com.alibaba.cloud
            spring-cloud-alibaba-sentinel-gateway
        

在这个整合包里边已经帮我们做了一系列的配置,就不需要我们在去手动配置。

3.到sentinel控制台中添加流控规则


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5719667.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存