Gateway作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作往往是通过网关提供的过滤器来实现的。之前写的给url添加前缀或者去除前缀都是用过滤器实现的。
过滤器名称 | 说明 |
---|---|
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
自定义一个获取请求头消息的过滤器
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的值
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)spring cloud gateway 默认使用redis的RateLimter限流算法来实现。所以我们要使用首先需要引入redis的依赖
<!‐‐redis‐‐>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring‐boot‐starter‐data‐redis‐reactiveartifactId>
<version>2.1.3.RELEASEversion>
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 #令牌桶总容量
解释:
通过在replenishRate
和burstCapacity
中设置相同的值来实现稳定的速率。
设置burstCapacity
高于replenishRate
时,可以允许临时突发。在这种情况下,需要在这段突发时间之间允许速率限制器(根据 replenishRate
),因为 2 个连续的突发将导致请求被丢弃(HTTP 429 - Too Many Requests)。
key-resolver: “#{@ipKeyResolver}” 用于通过SPEL表达式来指定使用哪一个KeyResolver.
如上配置:
表示 一秒内,允许 一个请求通过,令牌桶的填充速率也是一秒钟添加一个令牌。
最大突发状况 也只允许 一秒内有一次请求,可以根据业务来调整 。