专栏首页大数据学习笔记SpringCloud 2.x学习笔记:15、Spring Cloud Gateway之Filter过滤器(Greenwich版本)

SpringCloud 2.x学习笔记:15、Spring Cloud Gateway之Filter过滤器(Greenwich版本)

1、AddRequestHeader过滤器

server:
  port: 7013
---
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: http://httpbin.org
        filters:
        - AddRequestHeader=X-Request-Flag, HelloWorld
        predicates:
        - After=2019-06-20T00:00:00+08:00[Asia/Shanghai]
  profiles: add_request_header_route

http://localhost:7013/get

AddRequestHeaderGatewayFilterFactory的源码

package org.springframework.cloud.gateway.filter.factory;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.http.server.reactive.ServerHttpRequest;

/**
 * @author Spencer Gibb
 */
public class AddRequestHeaderGatewayFilterFactory
		extends AbstractNameValueGatewayFilterFactory {

	@Override
	public GatewayFilter apply(NameValueConfig config) {
		return (exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest().mutate()
					.header(config.getName(), config.getValue()).build();

			return chain.filter(exchange.mutate().request(request).build());
		};
	}

}

从代码可知道,由当前的ServerHttpRequest创建新 ServerHttpRequest ,并在新的ServerHttpRequest加一个请求头,然后创建新的 ServerWebExchange ,提交过滤器链继续过滤。

2、AddResponseHeader过滤器

---
spring:
  cloud:
    gateway:
      routes:
      - id: add_response_header_route
        uri: http://httpbin.org:80/get
        filters:
        - AddResponseHeader=X-Response-Flag, Hadron
        predicates:
        - After=2019-06-20T00:00:00+08:00[Asia/Shanghai]
  profiles: add_response_header_route
C:\Windows\System32>curl -I localhost:7013
HTTP/1.1 200 OK
X-Response-Flag: Hadron
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Date: Fri, 21 Jun 2019 09:01:14 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Length: 0

3、RewritePath 过滤器

---
spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://blog.csdn.net/chengyuqiang
        predicates:
        - Path=/foo/**
        filters:
        - RewritePath=/foo/(?<segment>.*), /$\{segment}
  profiles: rewritepath_route

RewritePath 过滤器将/foo/(?.*)重写为{segment},然后转发到https://blog.csdn.net。 比如请求http://localhost:7013/foo/chengyuqiang,RewritePath 过滤器将/foo/chengyuqiang重写为chengyuqiang,然后转发到https://blog.csdn.net,这样路径就是https://blog.csdn.net/chengyuqiang

http://localhost:7013/foo/chengyuqiang

4、PrefixPath过滤器

---
spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://blog.csdn.net
        predicates:
        - Path=/article/**
        filters:
        - PrefixPath=/chengyuqiang
  profiles: prefixpath_route

比如:请求/hello,最后转发到目标服务的路径变为/chengyuqiang/hello

http://localhost:7013/article/details/85019277

注意,这个页面会再次跳转到https://www.csdn.net/首页

5、StripPrefix过滤器

---
spring:
  cloud:
    gateway:
      routes:
      - id: stripprefix_route
        uri: https://httpbin.org
        predicates:
        - Path=/my/**
        filters:
        - StripPrefix=2
  profiles: stripprefix_route

比如,请求/my/bar/get,( StripPrefix=2)去除掉前面两个前缀之后,最后转发到目标服务的路径为/get

http://localhost:7013/my/bar/get

6、自定义过滤器

下面,我们自定义一个filter用来统计每次请求的时长。

package com.cntaiping.tpa.gatewayfilter.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class MyFilter implements GatewayFilter, Ordered {

    private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //记录请求开始时间,并保存在ServerWebExchange中
        exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());

        return chain.filter(exchange)//“pre”类型的过滤器
                .then(Mono.fromRunnable(// run()方法中相当于"post"过滤器
                () ->{
                    Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
                    if (startTime != null) {
                        System.out.println(exchange.getRequest().getURI() + " 耗时" + (System.currentTimeMillis() - startTime));
                    }
                }
        ));
    }

    @Override
    public int getOrder() {
        //设定优先级别的,值越大则优先级越低
        return 0;
    }
}

将自定义filter注册到路由中

package com.cntaiping.tpa.gatewayfilter;

import com.cntaiping.tpa.gatewayfilter.filter.MyFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayFilterApplication.class, args);
    }

    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/my/**")
                        .filters(f -> f.filter(new MyFilter())
                                .addResponseHeader("X-Response-Default-Flag", "Default-Flag"))
                        .uri("http://httpbin.org:80/get")
                        .order(0)
                        .id("my_filter_router")
                )
                .build();
    }

}

重启服务

curl localhost:7013/my/123

6、自定义过滤器工厂

下面演示自定义过滤器工厂类,这样就可以非常方便的在配置文件中配置过滤器。

springboot约定过滤器工厂的前缀为配置的name,所以自定义的过滤器工厂类的后缀是GatewayFilterFactory

package com.cntaiping.tpa.gatewayfilter.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import reactor.core.publisher.Mono;

import java.util.*;

public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
    private Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * 定义可以再yaml中声明的属性变量
     */
    private static final String TYPE = "type";
    private static final String OP = "op";

    public MyGatewayFilterFactory(){
        // 这里需要将自定义的config传过去,否则会报告ClassCastException
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList(TYPE, OP);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return ((exchange, chain) -> {
            boolean root = "root".equals(config.getOp());
            if (root){
                logger.info("GatewayFilter root");
            }
            else {
                logger.info("GatewayFilter customer");
            }
            // 在then方法里的,相当于aop中的后置通知
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                // do something
                logger.info(System.currentTimeMillis()+"");
            }));
        });
    }

    /**
     * 自定义的config类,用来设置传入的参数
     */
    public static class Config {

        /**
         * 过滤类型
         */
        private String type;

        /**
         * 操作
         */
        private String op;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getOp() {
            return op;
        }

        public void setOp(String op) {
            this.op = op;
        }
    }
}
package com.cntaiping.tpa.gatewayfilter;

import com.cntaiping.tpa.gatewayfilter.filter.MyFilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyGatewayFilterFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayFilterApplication.class, args);
    }

/*    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/my/**")
                        .filters(f -> f.filter(new MyFilter())
                                .addResponseHeader("X-Response-Default-Flag", "Default-Flag"))
                        .uri("http://httpbin.org:80/get")
                        .order(0)
                        .id("my_filter_router")
                )
                .build();
    }*/

    @Bean
    public MyGatewayFilterFactory exampleGatewayFilterFactory(){
        return new MyGatewayFilterFactory();
    }

}
---
spring:
  cloud:
    gateway:
      routes:
      - id: myfilter_route
        uri: http://httpbin.org:80/get
        filters:
        - name: My
          args:
            op: root
            type: he
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  profiles: myfilter_route

7、global过滤器

package com.cntaiping.tpa.gatewayfilter.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class TokenFilter implements GlobalFilter, Ordered {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 该全局过滤器会校验请求中是否包含token请求参数
     * 如何不包含,则不转发路由;否则执行正常的逻辑。
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (token == null || token.isEmpty()) {
            logger.info( "token is empty..." );
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -100;
    }
}
package com.cntaiping.tpa.gatewayfilter;

import com.cntaiping.tpa.gatewayfilter.filter.MyFilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyGatewayFilterFactory;
import com.cntaiping.tpa.gatewayfilter.filter.TokenFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GatewayFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayFilterApplication.class, args);
    }

/*    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/my/**")
                        .filters(f -> f.filter(new MyFilter())
                                .addResponseHeader("X-Response-Default-Flag", "Default-Flag"))
                        .uri("http://httpbin.org:80/get")
                        .order(0)
                        .id("my_filter_router")
                )
                .build();
    }*/

    @Bean
    public MyGatewayFilterFactory exampleGatewayFilterFactory(){
        return new MyGatewayFilterFactory();
    }

    @Bean
    public TokenFilter tokenFilter(){
        return new TokenFilter();
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringCloud 2.x学习笔记:8、Spring Cloud Sleuth(Greenwich版本)

    从spring Cloud为F版本开始,已经不需要自己构建Zipkin Server了,只需要下载jar运行即可。

    程裕强
  • Java Web(SpringBoot 2.x)上传文件夹,完整代码

    程裕强
  • java.lang.NoSuchMethodError: org.elasticsearch.action.support.master.AcknowledgedResponse

    国外用户也遇到类似的错误 https://stackoverflow.com/questions/53755092/i-got-a-java-lang-nos...

    程裕强
  • Spring Cloud Gateway快速体验

    GlobalFilter只要注册到Spring容器,就可以应用在所有请求,比如监控请求耗时

    十毛
  • SpringBoot中实现拦截器级别的URl访问过快拦截,并利用JPA实现IP黑名单的功能。

    今天给大家介绍一下SpringBoot中实现拦截器级别URl过快访问拦截,并利用JPA实现IP黑名单的功能。 上一节中已经将中已经介绍了在控制器层面上面的URL...

    林老师带你学编程
  • SpringBoot入门建站全系列(十七)整合ActiveMq(JMS类消息队列)

    消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间...

    品茗IT
  • Spring Batch之批处理实践

    Spring Batch 是Spring的子项目,基于Spring的批处理的框架,通过其可以构建出批量的批处理框架。

    mySoul
  • 【SpringSecurity系列01】初识SpringSecurity

    ​ 用自己的话 简单介绍一下,Spring Security基于 Servlet 过滤器链的形式,为我们的web项目提供认证与授权服务。它来自于S...

    yukong
  • java架构之路-(spring源码篇)由浅入深-spring实战详细使用

      今天我更新了一篇jvm垃圾回收的算法和垃圾回收器的内部逻辑,但是看的人不多啊......貌似大家还是比较喜欢看源码吧,毕竟实战要比理论用的多。

    小菜的不能再菜
  • rabbitMQ实现可靠消息投递 原

        RabbitMQ消息的可靠性主要包括两方面,一方面是通过实现消费的重试机制(通过@Retryable来实现重试,可以设置重试次数和重试频率,但是要保证幂...

    chinotan

扫码关注云+社区

领取腾讯云代金券