AI写作智能体 自主规划任务,支持联网查询和网页读取,多模态高效创作各类分析报告、商业计划、营销方案、教学内容等。 广告
## 一、自定义全局过滤器-统计接口api响应时长 我们用一个常见的需求:api接口服务的响应时长的计算,这个需求的实现对请求访问链路的优化很有意义。具体实现看下文的代码及注释: ~~~ @Configuration public class GlobalGatewayFilterConfig { @Bean @Order(-100) public GlobalFilter apiGlobalFilter() { return (exchange, chain) -> { //获取请求处理之前的时间 Long startTime = System.currentTimeMillis(); //请求处理完成之后 return chain.filter(exchange).then().then(Mono.fromRunnable(() -> { //获取请求处理之后的时间 Long endTime = System.currentTimeMillis(); //这里可以将结果进行持久化存储,我们暂时简单处理打印出来 System.out.println( exchange.getRequest().getURI().getRawPath() + ", cost time : " + (endTime - startTime) + "ms"); })); }; } } ~~~ * `@Order`注解值越小,表示过滤器执行的优先级越高 我们使用《自定义PredicateFactory》那一节同样的测试用例,进行一下测试。zimug-server-gateway后台的打印结果如下: ![](https://img.kancloud.cn/97/71/977181e5a152d202000acb55f1b1ff9a_559x46.png) 通过上面的方法,可以在一个配置类里面写多个函数,每一个函数代表一个全局过滤器。 ## 二、以class类的形式书写全局过滤器 上面的方法,当过滤器函数的实现内容比较复杂的时候,会导致单个类的代码行数过多,我们可以一个类写一个过滤器。 ~~~ @Component public class ApiGlobalFilter implements GlobalFilter, Ordered { @Override public int getOrder() { return -100; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { //获取请求处理之前的时间 Long startTime = System.currentTimeMillis(); //请求处理完成之后 return chain.filter(exchange).then().then(Mono.fromRunnable(() -> { //获取请求处理之后的时间 Long endTime = System.currentTimeMillis(); //这里可以将结果进行持久化存储,我们暂时简单处理打印出来 System.out.println( exchange.getRequest().getURI().getRawPath() + ", cost time : " + (endTime - startTime) + "ms"); })); } } ~~~ ## 三、自定义局部过滤器-指定IP访问 在我们的系统中可能有几个功能是专门给系统管理员使用的,并不广泛开放。我们假设这样一个需求:只让某个ip(管理员操作的PC的IP)的客户端访问aservice-rbac权限管理服务,其他的ip不可以。 * 自定义Filter工厂需要继承 AbstractGatewayFilterFactory类,重写 apply 方法的逻辑。 * 在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。 * 在 apply 方法中可以通过chain操作过滤器链 ~~~ @Component @Order(99) public class IPForbidGatewayFilterFactory extends AbstractGatewayFilterFactory<IPForbidGatewayFilterFactory.Config> { public IPForbidGatewayFilterFactory() { super(Config.class); } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("permitIp"); //对应config类的参数 } @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { //获取服务访问的客户端ip String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); if (config.getPermitIp().equals(ip)) { //如果客户端ip=permitIp,继续执行过滤器链允许继续访问 return chain.filter(exchange); } //否则返回,拒绝请求 exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); return exchange.getResponse().setComplete(); }; } static public class Config { private String permitIp; public String getPermitIp() { return permitIp; } public void setPermitIp(String permitIp) { this.permitIp = permitIp; } } } ~~~ * 类的命名需要以 GatewayFilterFactory结尾,比如 IPForbidGatewayFilterFactory,那么在配置文件中使用该Filter的时候 IPForbid就是这个Filter工厂的名称。 * Config类可以定义一个或多个属性,要重写List shortcutFieldOrder()这个方法指定属性名称。 配置文件,因为只有一个参数,所以下图中的`192.168.1.6`将赋值给config类的唯一参数:permitIp ![](https://img.kancloud.cn/b9/ad/b9add210d0bc43d887a7b9b74e3e5d97_549x454.png) 如果我们从不是`192.168.1.6`的这个客户端ip进行接口访问测试,将得到如下的结果: ![](https://img.kancloud.cn/22/2a/222ac5992cfe243b01bf347e1a5aaf60_1392x376.png) **如何为GatewayFilterFactory配置多个参数?** 首先Config要有多个成员变量,如:permitIp、xxxx,其次配置文件进行如下配置 ![](https://img.kancloud.cn/17/7a/177ac4dbc160fc3c55be83f8534c58f0_563x462.png)