前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud 2.x学习笔记:15、Spring Cloud Gateway之Filter过滤器(Greenwich版本)

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

作者头像
程裕强
发布2019-07-02 10:44:28
8780
发布2019-07-02 10:44:28
举报

1、AddRequestHeader过滤器

代码语言:javascript
复制
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
代码语言:javascript
复制
在这里插入图片描述
在这里插入图片描述

http://localhost:7013/get

在这里插入图片描述
在这里插入图片描述

AddRequestHeaderGatewayFilterFactory的源码

代码语言:javascript
复制
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过滤器

代码语言:javascript
复制
---
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
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
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 过滤器

代码语言:javascript
复制
---
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过滤器

代码语言:javascript
复制
---
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过滤器

代码语言:javascript
复制
---
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用来统计每次请求的时长。

代码语言:javascript
复制
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注册到路由中

代码语言:javascript
复制
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();
    }

}

重启服务

代码语言:javascript
复制
curl localhost:7013/my/123
在这里插入图片描述
在这里插入图片描述

6、自定义过滤器工厂

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

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

代码语言:javascript
复制
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;
        }
    }
}
代码语言:javascript
复制
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();
    }

}
代码语言:javascript
复制
---
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过滤器

代码语言:javascript
复制
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;
    }
}
代码语言:javascript
复制
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();
    }
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年06月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、AddRequestHeader过滤器
  • 2、AddResponseHeader过滤器
  • 3、RewritePath 过滤器
  • 4、PrefixPath过滤器
  • 5、StripPrefix过滤器
  • 6、自定义过滤器
  • 6、自定义过滤器工厂
  • 7、global过滤器
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档