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 對象。
通過在replenishRate
和burstCapacity
中設置相同的值來實現穩定的速率。
設置burstCapacity
高於replenishRate
時,可以允許臨時突發。在這種情況下,需要在這段突發時間之間允許速率限制器(根據 replenishRate
),因爲 2 個連續的突發將導致請求被丟棄(HTTP 429 - Too Many Requests)。
key-resolver: “#{@ipKeyResolver}” 用於通過SPEL表達式來指定使用哪一個KeyResolver.
如上配置:
表示 一秒內,允許 一個請求通過,令牌桶的填充速率也是一秒鐘添加一個令牌。
最大突發狀況 也只允許 一秒內有一次請求,可以根據業務來調整 。