Spring Cloud Gateway——(二)微服務網關過濾器和網關限流

Spring Cloud Gateway——(二)微服務網關過濾器和網關限流

1.4 微服務網關過濾器

Gateway作爲網關的其中一個重要功能,就是實現請求的鑑權。而這個動作往往是通過網關提供的過濾器來實現的。之前寫的給url添加前綴或者去除前綴都是用過濾器實現的。

  • Gateway自帶過濾器有幾十個,我常用的自帶過濾器有:
過濾器名稱 說明
AddRequestHeader 對匹配上的請求加上Header
AddRequestParameters 對匹配上的請求路由添加參數
AddResponseHeader 對從網關返回的響應添加Header
StripPrefix 對匹配上的請求路徑去除前綴

更多過濾器和詳細的說明在官網鏈接

  • 配置全局默認過濾器

這些自帶的過濾器可以和之前使用去除url前綴的用法類似,也可以將這些過濾器配置成不只是針對某個路由;而是可以對所有路由生效,也就是配置默認過濾器:

spring:
  application:
    name: gateway
  cloud:
    gateway:
    # 默認過濾器,對所有路由生效
	  default-filters:
		# 響應頭過濾器,對輸出的響應設置其頭部屬性名稱爲X-Response-Default-MyName,值爲xm;如果有多個參數多則重寫一行設置不同的參數
	    - AddResponseHeader=X-Response-Default-MyName, xm

1.5 自定義過濾器

1.5.1 自定義局部過濾器

自定義一個獲取請求頭消息的過濾器

package com.xm.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @title: MyParamGatewayFilterFactory
 * @projectName: spring_cloud
 * @description: TODO
 * @author: Tzh
 * @date: 2019/11/25  19:06
 */
@Component
public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.MyParam> {
    public static final String PARAM_NAME = "param";
    public MyParamGatewayFilterFactory() {
        super(MyParam.class);
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(PARAM_NAME);
    }
    @Override
    public GatewayFilter apply(MyParam config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            if (request.getQueryParams().containsKey(config.param)) {
                request.getQueryParams().get(config.param).
                        forEach(value -> System.out.printf("---MyParamGatewayFilterFactory--- %s = %s ---\n",config.param,value));
            }
            return chain.filter(exchange);
        };
    }
    public static class MyParam{
        public String param;
        public String getParam() {
            return param;
        }
        public void setParam(String param) {
            this.param = param;
        }
    }
}

寫好配置類後只需要在yml中配置需要獲取請求中key的值就可以了

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
      - id: user-service-route
        uri: lb://user-service
        predicates:
        - Path=/api/user/**
        filters:
          - MyParam=name # 配置後就可以獲取請求中key爲name的值

1.5.2 自定義全局過濾器

package com.xm.gateway.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;

/**
 * @title: MyGlobalFilter
 * @projectName: 
 * @description: TODO
 * @author: Tzh
 * @date: 2019/11/25  19:45
 */
@Component
public class MyGlobalFilter implements GlobalFilter , Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("-----------------全局過濾器MyGlobalFilter---------------------\n");
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isBlank(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
    //設置過濾器的優先級,值越小優先級越高
    @Override
    public int getOrder() {
        return 1;
    }
}

1.6 網關限流

(1)spring cloud gateway 默認使用redis的RateLimter限流算法來實現。所以我們要使用首先需要引入redis的依賴

<!‐‐redis‐‐>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring‐boot‐starter‐data‐redis‐reactive</artifactId>
	<version>2.1.3.RELEASE</version>
</dependency>

(2)在工程中創建配置類,定義KeyResolver,KeyResolver用於計算某一個類型的限流的KEY也就是說,可以通過KeyResolver來指定限流的Key。

	/**
     * 定義一個KeyResolver
     */
    @Bean
    public KeyResolver ipKeyResolver() {
        return new KeyResolver() {
            @Override
            public Mono<String> resolve(ServerWebExchange exchange) {
                return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
            }
        };
    }

(3)修改application.yml中配置項,指定限制流量的配置以及REDIS的配置

	  # 商品服務
      - id: goods
        uri: lb://goods # 商品服務在Eureka上註冊的名字
        predicates:
        - Path=/goods/** # 攔截的路徑
        filters:
        - StripPrefix= 1 # url前綴第一個丟棄
        - PrefixPath=/goods/v1 # 添加url前綴 /goods/v1
        - name: RequestRateLimiter #請求數限流 名字不能隨便寫
          args:
            key-resolver: "#{@ipKeyResolver}"
            redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
            redis-rate-limiter.burstCapacity: 1 #令牌桶總容量

解釋:

  • burstCapacity:令牌桶總容量。
  • replenishRate:令牌桶每秒填充平均速率。
  • key-resolver:用於限流的鍵的解析器的 Bean 對象的名字。它使用 SpEL 表達式根據#{@beanName}從 Spring 容器中獲取 Bean 對象。

通過在replenishRateburstCapacity中設置相同的值來實現穩定的速率。

設置burstCapacity高於replenishRate時,可以允許臨時突發。在這種情況下,需要在這段突發時間之間允許速率限制器(根據 replenishRate),因爲 2 個連續的突發將導致請求被丟棄(HTTP 429 - Too Many Requests)。

key-resolver: “#{@ipKeyResolver}” 用於通過SPEL表達式來指定使用哪一個KeyResolver.
如上配置:
表示 一秒內,允許 一個請求通過,令牌桶的填充速率也是一秒鐘添加一個令牌。
最大突發狀況 也只允許 一秒內有一次請求,可以根據業務來調整 。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章