1. Filter介绍
Filter是实现在网关路由之前或之后加入一些逻辑,或者拦截过滤的工具, 称为过滤器。 在Spring Cloud Gateway中除了内置的Filter之外,也可以自定义Filter来实现自己想要的功能。
原理图如下:
2. 内置Filter
Spring cloud gateway 内置了很多的filter,单一的有32种,全局的有9种。这个数量实在是太惊人了,而且用法都比较简单,所以这里大家可以自行根据官网给出的演示进行练习 官方网址:Spring Cloud Gateway
GateWay内置的Filter生命周期为两种:
-
pre(业务逻辑之前)
-
post(业务逻辑之后)
GateWay本身自带的Filter分为两种:
-
GateWayFilter(单一)
-
GlobalFilter(全局)
StripPrefix
这是一个内置的Filter,其功能是:将请求发送到下游之前要从请求中剥离部分路径。
需求如下:
我们有个后端服务,路径为http://localhost:8081/getServerPort,这个服务是其他人提供的,这个路径我们改不了, 但是我们网关提供的请求地址是带/test开头的, 例如:http://localhost:8888/test/getServerPort。这个访问地址我们也不能改,因为还有其他地方也是类似的地址,不能改统一的规则, 现在需要将这个地址路由到后端http://localhost:8081/getServerPort上,我们就可以通过StripPrefix来实现。
后端服务接口代码
@RestController
public class TestController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/getServerPort")
public String getServerPort() {
return "Hello Nacos Discovery Port:" + serverPort;
}
}
配置网关
server.port=8888
spring.application.name=gateway-app
spring.cloud.nacos.discovery.server-addr=192.168.43.11:8848
management.endpoints.web.exposure.include=*
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.routes[0].id=nacos-provider
spring.cloud.gateway.routes[0].uri=lb://nacos-provider
# 访问路径Path=/test/**
spring.cloud.gateway.routes[0].predicates[0]=Path=/test/**
# 网关访问/test/** 时,将转发给nacos-provider服务,会去除第一个路径/test。
# 所以最后访问地址是lb://nacos-provider/**
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
通过网关访问服务
3. 自定义Filter
自定义filter也可以实现两种,一种是全局生效的,一种是某种路由生效的,需要配置。 我们先来实现,某种路由生效的,它要相对复杂一些。
1. 需求如下
我们有个后端服务,路径为http://localhost:8081/test/getServerPort,这个服务是其他人提供的,这个路径我们改不了, 但是我们网关提供的请求地址是不带/test开头的, 例如:http://localhost:8888/getServerPort。这个访问地址我们也不能改,因为还有其他地方也是类似的地址,不能改统一的规则, 现在需要将这个地址路由到后端http://localhost:8081/test/getServerPort上,我们就可以通过自定义Filter来实现。
可以看出该需求刚好和上一节的需求相反。
2. 建立AddPrefixFilter
这个AddPrefixFilter需要继承自AbstractGatewayFilterFactory<AddPrefixFilter.Config>
@Component
@Slf4j
public class AddPrefixFilter extends AbstractGatewayFilterFactory<AddPrefixFilter.Config> {
public AddPrefixFilter() {
//指定可接收配置数据的类
super(AddPrefixFilter.Config.class);
}
public List<String> shortcutFieldOrder() {
//返回可配置的字段
return Collections.singletonList("prefix");
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest req = exchange.getRequest();
String newPath = config.prefix + req.getURI().getRawPath();
ServerHttpRequest request = req.mutate().path(newPath).build();
return chain.filter(exchange.mutate().request(request).build());
};
}
@Override
public String name() {
//返回用于配置的名称
return "AddPrefix";
}
@Getter
@Setter
public static class Config {
//用于接收可配置字段的值
private String prefix;
}
}
3. 添加配置如下
server.port=8888
spring.application.name=gateway-app
spring.cloud.nacos.discovery.server-addr=192.168.43.11:8848
management.endpoints.web.exposure.include=*
spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.routes[0].id=nacos-provider
spring.cloud.gateway.routes[0].uri=lb://nacos-provider
# 访问路径Path=/test/**
spring.cloud.gateway.routes[0].predicates[0]=Path=/**
# 自定义过滤器AddPrefix,在访问uri时添加/test路径在url前面
spring.cloud.gateway.routes[0].filters[0]=**AddPrefix=/test**
4. 后端服务接口
@RestController
public class TestController implements ProviderOpenApis {
@Value("${server.port}")
private String serverPort;
@GetMapping("/test/getServerPort")
public String getServerPort() {
return "Hello Nacos Discovery Port:" + serverPort;
}
}
5. 测试
4. 自定义全局Filter
自定义全局filter相对简单一些,因为全局filter不用管具体的那个路由器才生效。 所以在全局只有一个filter。
1. 需求如下
进入系统时如果参数中没有username用户名,则人为这个请求是非法请求,否则就通过请求。
2. 代码如下
import lombok.extern.slf4j.Slf4j;
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;
/**
* 进入系统时如果参数中没有username用户名,则人为这个请求是非法请求,否则就通过请求。
* 实现Ordered,需要返回一个整数,表示加载过滤器的顺序, 整数数字越小优先级越高
* 实现GlobalFilter,实现过滤器逻辑
*/
@Component
@Slf4j
public class UserNameCheckFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String username = exchange.getRequest().getQueryParams().getFirst("username");
if (username == null) {
//如果username为空,返回状态码为406,不可接受的请求
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
3. 测试
访问时不带用户名username字段,返回406
访问是带了username,正常请求
5. Spring cloud gateway中的默认filter
具体请参考官方文档:
可以使用翻译成中文查看。