Spring cloud gateway的使用

目录:
1.词汇表
2.工作原理
3.配置路由谓词工厂和网关过滤工厂
········一. 熔断
········二. 限流
········三. 重试
········四. 请求大小
········五. 默认过滤器(全局)
········六. 全局过滤器
················1).结合全局过滤器和网关过滤器排序
········七. HTTP超时配置
················1).全局超时
················2).单个路由超时
········八. CORS跨域
········九. 执行器API
················1).详细执行器格式
················2).检索路由过滤器
························1>.全局过滤器
························2>.路由过滤器
················3).刷新路由缓存
················4).检索网关中定义的路由
················5).检索关于特定路由的信息
················6).创建和删除特定路线
················7).重述:所有端点的列表

* 	Spring Cloud Gateway是基于Spring Boot 2.x,Spring WebFlux和Project Reactor 构建的。因此,当您使用Spring Cloud Gateway时,许多您熟悉的同步库(例如,Spring Data和Spring Security)和模式可能不适用。如果您不熟悉这些项目,建议您在使用Spring Cloud Gateway之前先阅读它们的文档以熟悉一些新概念。


* Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行时。它在传统的Servlet容器中或作为WAR构建时不能工作。

1.词汇表

  • 路线:网关的基本构建块。它由ID,目标URI,谓词集合和过滤器集合定义。如果聚合谓词为true,则匹配路由。
  • 谓词:这是Java 8 Function谓词。输入类型是Spring Framework ServerWebExchange。这使您可以匹配HTTP请求中的所有内容,例如标头或参数。
  • Filter:这些是使用特定工厂构造的Spring Framework GatewayFilter实例。在这里,您可以在发送下游请求之前或之后修改请求和响应。

2.工作原理

下图从总体上概述了Spring Cloud Gateway的工作方式:

在这里插入图片描述

​ 客户端向Spring Cloud Gateway发出请求。如果网关处理程序映射确定请求与路由匹配,则将其发送到网关Web处理程序。该处理程序通过特定于请求的过滤器链来运行请求。筛选器由虚线分隔的原因是,筛选器可以在发送代理请求之前和之后运行逻辑。所有“前置”过滤器逻辑均被执行。然后发出代理请求。发出代理请求后,将运行“后”过滤器逻辑。

3.配置路由谓词工厂和网关过滤工厂

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route      	#唯一标识
        uri: https://example.org  	#转发路径
        predicates:				   #谓词集合
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]  #匹配在指定日期时间之后发生的请求
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver] #匹配在指定日期时间之前发生的请求
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] #匹配在指定日期之后及指定日期之前的请求
        - Header=X-Request-Id, \d+ #标头路由谓词工厂
        - Host=**.somehost.org,**.anotherhost.org #主机路由谓词工厂
        - Cookie=mycookie,mycookievalue #cookie路由谓词工厂
        - Method=GET,POST #方法路由(该路由支持post和get)
        - Path=/red/{segment},/blue/{segment} #路径路由(匹配/red/..或/blue/..的路由)
        - Query=green #查询路由(匹配带green参数的路由)
        - Query=red, gree. # 如果请求包含一个red查询参数,其值与gree(正则)匹配,则前面的路由将匹配。
        - RemoteAddr=192.168.1.1/24 #远程地址路由(如果请求的远程地址是192.168.1.10,则此路由匹配。)
        
        #===========
     - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
     - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2   

备注:

1.要设置时间可以搜索 "America/Denver时间"来根据情况设置

重要:

* 1).当spring cloud 的版本为Hoxton.RELEASE,gateway的版本显示为2.2.0,这个时候 - Method=GET,POST配置只有GET生效,spring cloud的版本改为Hoxton.SR3全部生效

一. 熔断

Netflix已经将Hystrix置于维护模式。我们建议您使用带有Resilience4J的Spring Cloud断路器网关过滤器,因为对Hystrix的支持将在未来的版本中被移除

  • Resilience4j 是受Netflix的Hysrix项目启发,专门为Java 8 和函数式编程设计的轻量级容错框架

    **Hystrix是Netflix的一个实现断路器模式的库。Hystrix网关过滤器允许您将断路器引入网关路由,保护您的服务免受级联故障的影响,并允许您在下游故障时提供后备响应。**
    
  • 使用断路器功能
  • 1).第一步在gateway服务中导入pom依赖
		<!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
  • 2).在application.yml中配置
- id: FallbackController  # 断路器
  uri: lb://data
  predicates:
    - Path=/fall
  filters:
    - name: Hystrix
      args:
        name: fallbackcmd
        fallbackUri: forward:/defaultFallback
- id: defaultFallback  # 熔断方法
  uri: lb://data
  predicates:
    - Path=/defaultFallback
        
hystrix:
  command:
    fallbackcmd:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 5000 #超时时间,若不设置超时时间则有可能无法触发熔断

  • 3).配置回调方法
@RestController
public class HystrixController {

    @GetMapping("/defaultFallback")
    public Map<String,Object> fallback() {
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("Code",100);
        map.put("Message","服务暂时不可用");
        return map;
    }
}
  • 备注:

    在上面2).yml配置中触发熔断后转发路由,需要转发到一个新的实例上,这样才能正常的触发熔断。

二. 限流

重要:

使用限流功能,必须配合Redis使用(切记切记!!!)

​ 在本地测试不写redis的配置会默认去连接localhost:6379,找不到将无法正常使用限流功能。

  • 使用限流功能
  • 1).第一步在gateway服务中导入pom依赖
<!--限流-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

2).在application.yml中配置

示例代码:

- id: RateLimiterOneController
  uri: lb://data
  predicates:
    - Path=/RateLimiterOne/demo
  filters:
    - name: RequestRateLimiter # 使用限流名称必须是这个
      args:
        redis-rate-limiter.replenishRate: 10   # 允许用户每秒执行多少请求
        redis-rate-limiter.burstCapacity: 20   # 用户在一秒内允许的最大求请数,设置为0将阻塞所有请求
        redis-rate-limiter.requestedTokens: 1  # 表示一个请求需要多少个令牌
        Key-resolver: "#{@userKeyResolver}"    # 没有这个参数请求将无法进入(方法在gateway启动类中)
        #如设置replenishRate =1 requestedTokens = 60和burstCapacity = 60将导致限制1请求/分钟

3).配置限流的方式

备注:

​ gateway了解到的限流的方式有三种分别为(用户),(uri),(Hostname)

  • 方式一:

@SpringBootApplication
@EnableDiscoveryClient
public class GatawayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatawayApplication.class, args);
    }
    /**
     * 根据用户维度限流(用户,uri,主机名三选一)
     * @return
     */
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }
    
    /**
     * 根据hostname限流
     * @return
     */
//    @Bean
//    KeyResolver  hostAddrKeyResolver() {
//        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
//    }
    
    /**
     * 根据uri限流
     * @return
     */
//    @Bean
//    KeyResolver uriKeyResolver() {
//        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
//    }
}
  • 方式二:
@Component
public class MyKeyResolver {

    /**
     * 根据用户维度限流(用户,uri,主机名三选一)
     * @return
     */
    @Bean
    KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
    }
}

.....

测试结果:

​ 如上面yml的配置,一个主机/用户/uri每秒只能请求10次,超出10次将返回429的错误。

三. 重试

当将重试过滤器与任何具有主体的HTTP方法一起使用时,主体将被缓存,并且网关将受到内存的限制。正文被缓存在由定义的请求属性中ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR。对象的类型是org.springframework.core.io.buffer.DataBuffer

The following defaults are configured for Retry filter, if enabled:

  • retries: Three times
  • series: 5XX series
  • methods: GET method
  • exceptions: IOException and TimeoutException
  • backoff: disabled
- id: RetryController
  uri: lb://data
  predicates:
    - Path=/Retry/test
  filters:
    - name: Retry
      args:
        retries: 3    # 重试次数(默认为3次)
        statuses: BAD_GATEWAY,INTERNAL_SERVER_ERROR    # 应重试的  HTTP状态码
        methods: GET,POST    # 应该重试的HTTP方法
        #series: # 要重试的一系列状态代码
        exceptions: java.io.IOException   # 应重试的引发异常的列表
        #backoff:  # 为重试配置的指数回退(默认关闭)
          #firstBackoff: 10ms
          #maxBackoff: 50ms
          #factor: 3
          #basedOnPreviousValue: false  # 是否基于以前的数值为基础

四. 请求大小

当请求大小大于允许的限制时,RequestSize GatewayFilter工厂可以限制请求到达下游服务。过滤器接受maxSize参数。maxSize是一个Datasize类型,因此可以将值定义为一个数字,后跟一个可选的DataUnit后缀,如“KB”或“MB”。字节的默认值是“B”。这是允许的尺寸限制。

spring:
  cloud:
    gateway:
      routes:
      - id: request_size_route
        uri: http://localhost:8080/upload
        predicates:
        - Path=/upload
        filters:
        - name: RequestSize
          args:
            maxSize: 5000000
  • RequestSize GatewayFilter工厂将响应状态设置为413负载太大,并在请求因大小而被拒绝时附加一个报头errorMessage。下面的例子显示了这样一个错误消息:
errorMessage` : `Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB

五. 默认过滤器(全局)

要添加过滤器并将其应用于所有路由,可以使用spring.cloud.gateway.default-filters。此属性采用过滤器列表。

spring:
  cloud:
    gateway:
      default-filters:
      - AddResponseHeader=X-Response-Default-Red, Default-Blue
      - PrefixPath=/httpbin

六. 全局过滤器

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

  • 注意:
    • 这个接口和它的用法可能会在将来的milestone版本中发生变化
1).结合全局过滤器和网关过滤器排序
  • gateway没有zuul那样丰富的生命周期,只有 “pre” 和 “post”

  • 由于Spring Cloud Gateway对筛选逻辑执行的“前置”和“后置”阶段进行了区分,因此优先级最高的筛选器是“前置”阶段的第一个筛选器,是“后置”阶段的最后一个筛选器。

方式一:

@Component
public class CustomGlobalFilter implements Ordered, GlobalFilter {
    /**
     * 执行时机,返回数值越小越先执行
     * @return
     */
    @Override
    public int getOrder() {
        return -1;
    }

    /**
     * 过滤器
     * @param exchange  当前服务器交换
     * @param chain     提供委托到下一个筛选器的方法
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String user = exchange.getRequest().getQueryParams().getFirst("user");
        // 判断参数中有user这个参数,将继续执行,没有将返回,本次请求结束
        if (StringUtils.isBlank(user)) {
            System.err.println("没有用户");
            return null;
        }
        System.err.println("first....");
        return chain.filter(exchange);
    }
}

方式二:

	@Bean
    @Order(2)
    public GlobalFilter first() {
        return (exchange,chain) ->{
            System.err.println("前置--one.....");
            
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                System.err.println("后置---1.....");
            }));
        };
    }

2).Forward Routing Filter

3).LoadBalancerClient Filter

4).Netty Routing Filter

5).Netty Write Response Filter

6).RouteToRequestUrl Filter

7).Websocket Routing Filter

8).Gateway Metrics Filter

9).Marking An Exchange As Routed

参考文章:

http://www.imooc.com/article/290821

七. HTTP超时配置

可以为所有路由配置Http超时(响应和连接),并为每个特定路由覆盖Http超时

1).全局超时

要配置全局http超时:

connect-timeout必须以毫秒为单位指定。

response-timeout必须指定为java.time.Duration

spring:
  cloud:
    gateway:
      httpclient:              # 全局配置
        connect-timeout: 1000  # 连接超时
        response-timeout: 5s   # 响应超时
2).单个路由超时

要配置每个路由超时:

connect-timeout必须以毫秒为单位指定。

response-timeout必须以毫秒为单位指定。

 - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

八. CORS跨域

方式一:

package com.ntimes.gateway.Cors;

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;

/**
 * @author FEI
 * @apiNote 跨域配置
 */
@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter() {
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        //cors跨域配置对象
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //是否允许携带cookie
        corsConfiguration.setAllowCredentials(true);
        //允许跨域访问的域名,可填写具体域名,*代表允许所有访问
        corsConfiguration.addAllowedOrigin("*");
        //允许访问类型:get  post 等,*代表所有类型
        corsConfiguration.addAllowedMethod("*");
        // 允许访问头
        corsConfiguration.addAllowedHeader("*");

        //配置源对象
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);

        //cors 过滤器对象  注意!CorsWebFilter不要导错包
        return new CorsWebFilter(urlBasedCorsConfigurationSource);
    }
}

方式二:

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

九. 执行器API

​ 网关执行器端点允许您监视Spring云网关应用程序并与之交互。要进行远程访问,必须在应用程序属性中通过HTTP或JMX启用和公开端点。

  • 第一步导入依赖
		<!--执行器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  • 第二步增加配置
# 执行器配置
# 默认为true
management.endpoint.gateway.enabled=true
management.endpoints.web.exposure.include=gateway

备注:

​ 除了以上配置不用再配置别的信息

1).详细执行器格式

Spring Cloud Gateway增加了一种新的、更详细的格式。它为每个路由添加了更多的细节,允许您查看与每个路由关联的谓词和过滤器,以及任何可用的配置。

  • 示例:
    • http://127.0.0.1:9001/actuator/gateway/routes
[
  {
    "predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
    "route_id": "add_request_header_test",
    "filters": [
      "[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]",
      "[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]",
      "[[PrefixPath prefix = '/httpbin'], order = 2]"
    ],
    "uri": "lb://testservice",
    "order": 0
  }
]
  • 默认情况下启用此功能。要禁用它,请设置以下属性:
spring.cloud.gateway.actuator.verbose.enabled=false
2).检索路由过滤器
1>.全局过滤器

要检索应用于所有路由的全局过滤器

  • 示例:
    • GET请求
    • http://127.0.0.1:9001/actuator/gateway/globalfilters
{
  "org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5": 10100,
  "org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@4f6fd101": 10000,
  "org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@
  "org.springframework.cloud.gateway.filter.ForwardRoutingFilter@10
  "org.springframework.cloud.gateway.filter.NettyRoutingFilter@1fbd
  "org.springframework.cloud.gateway.filter.ForwardPathFilter@33a71
  "org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@135064ea": 2147483637,
  "org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@23c05889": 2147483646
}
  • 该响应包含已就位的全局筛选器的详细信息。对于每个全局过滤器,都有一个过滤器对象的字符串表示形式(例如org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@77856cc5)和过滤器链中的相应顺序。
2>.路由过滤器

要检索应用于路由的网关过滤器工厂

  • 示例:
    • GET请求
    • http://127.0.0.1:9001/actuator/gateway/routefilters
{
  "[AddRequestHeaderGatewayFilterFactory@570ed9c configClass = AbstractNameValueGatewayFilterFactory.NameValueConfig]": null,
  "[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object]": null,
  "[SaveSessionGatewayFilterFactory@4449b273 configClass = Object]": null
}
  • 响应包含应用于任何特定路由的GatewayFilter工厂的详细信息。对于每个工厂,对应的对象都有一个字符串表示(例如,[SecureHeadersGatewayFilterFactory@fceab5d configClass = Object1)。注意,null值是由于端点控制器的实现不完整造成的,因为它试图在过滤器链中设置对象的顺序,而这并不适用于GatewayFilter工厂对象。
3).刷新路由缓存

若要清除路由缓存,请向/actuator/gateway/routes 发送PoST请求。请求返回一个没有响应体的200。

4).检索网关中定义的路由

要检索网关中定义的路由

  • 示例:
    • GET请求
    • http://127.0.0.1:9001/actuator/gateway/routes
[{
  "route_id": "first_route",
  "route_object": {
    "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@1e9d7e7d",
    "filters": [
      "OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory$$Lambda$436/674480275@6631ef72, order=0}"
    ]
  },
  "order": 0
},
{
  "route_id": "second_route",
  "route_object": {
    "predicate": "org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory$$Lambda$432/1736826640@cd8d298",
    "filters": []
  },
  "order": 0
}]
  • 响应包含网关中定义的所有路由的详细信息。下表描述了响应的每个元素(每个都是一个路由)的结构:
PathTypeDescription
route_idStringThe route ID.
route_object.predicateObjectThe route predicate.
route_object.filtersArrayThe GatewayFilter factories applied to the route.
orderNumberThe route order.
5).检索关于特定路由的信息

要检索关于单个路由的信息

  • 示例:
    • GET
    • http://127.0.0.1:9001/actuator/gateway/routes/{id }
{
  "id": "first_route",
  "predicates": [{
    "name": "Path",
    "args": {"_genkey_0":"/first"}
  }],
  "filters": [],
  "uri": "https://www.uri-destination.org",
  "order": 0
}]
  • 下表描述了响应的结构:
PathTypeDescription
idString路由 ID.
predicatesArray路由谓词的集合。每个项目都定义给定谓词的名称和自变量
filtersArray应用于路线的过滤器集合。
uriString路由的目标URI。
orderNumber路线顺序。
6).创建和删除特定路线

创建路由:

  • 示例:
    • POST
    • http://127.0.0.1:9001/gateway/routes/{id_route_to_create}
    • JSON格式同上

删除路由:

  • 示例:
    • DELETE
    • http://127.0.0.1:9001/gateway/routes/{id_route_to_delete}
7).重述:所有端点的列表

下面的表格总结了Spring Cloud Gateway执行器端点(注意每个端点都有/actuator/gateway作为基本路径)

DHTTP MethodDescription
globalfiltersGET显示应用于路由的全局过滤器列表
routefiltersGET显示GatewayFilter应用于特定路线的工厂列表。
refreshPOST清除路由缓存
routesGET显示网关中定义的路由列表
routes/{id}GET显示有关特定路线的信息
routes/{id}POST将新路由添加到网关
routes/{id}DELETE从网关中删除现有路由
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值