4. Spring Cloud Gateway自定义Filter

1. Filter介绍

Filter是实现在网关路由之前或之后加入一些逻辑,或者拦截过滤的工具, 称为过滤器。 在Spring Cloud Gateway中除了内置的Filter之外,也可以自定义Filter来实现自己想要的功能。

原理图如下:

2. 内置Filter

Spring cloud gateway 内置了很多的filter,单一的有32种,全局的有9种。这个数量实在是太惊人了,而且用法都比较简单,所以这里大家可以自行根据官网给出的演示进行练习 官方网址:Spring Cloud Gateway

GateWay内置的Filter生命周期为两种:

  1. pre(业务逻辑之前)

  2. post(业务逻辑之后)

    GateWay本身自带的Filter分为两种:

  3. GateWayFilter(单一)

  4. 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

具体请参考官方文档:

Spring Cloud Gateway

可以使用翻译成中文查看。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值