spring-cloud-gateway自定义组件实战

自定义Handler

Handler
从请求头中获取usernamepassword,模拟登陆请求

@Component
public class UserHandler {
    private UserService userService;

    public UserHandler(UserService userService) {
        this.userService = userService;
    }

    public Mono<ServerResponse> login(ServerRequest serverRequest) {
        return ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .body(Mono.fromSupplier(()->{
                    String username = serverRequest.headers().firstHeader("username");
                    String password = serverRequest.headers().firstHeader("password");
                    try{
                        boolean  success = userService.login(username, password);
                        return new Return(success,username+":"+password);
                    }catch (Exception e) {
                        return new Return(false,e.getMessage());
                    }

                }), Return.class);
    }
	
	//构造返回对象
    @Data
    @AllArgsConstructor
    public static class Return{
        private boolean success;
        private String msg;
    }
}

Service

@Component
public class UserService {

    public boolean login(String username,String password) {
        //todo form db;
        return true;
    }
}

Router

    @Bean
    public RouterFunction<ServerResponse> userRouter(UserHandler userhandler) {
        return nest(
                //相当于controller上的requestmapping
                path("/user"),
                route(GET("/login"), userhandler::login)
//                        .andRoute(GET("/date"), userha::getDate);
        );
    }

测试
在这里插入图片描述

自定义 Predicate

factory
自定义HeaderTokenRoutePredicateFactory,用来拦截所有请求头中必须包含指定的header

public class HeaderTokenRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderTokenRoutePredicateFactory.Config> {

    public HeaderTokenRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("headers", "strategy");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                HttpHeaders httpHeaders = exchange.getRequest().getHeaders();
                List<String> headers = config.getHeaders();
                if (headers == null || headers.isEmpty()) {
                    return true;
                }
                switch (config.getStrategy()) {
                    case AND:
                    	//策略是AND 时,请求头中必须包含所有header
                        return headers.stream().allMatch(header -> existHeaderFunc.apply(httpHeaders,header));
                    default:
                    	//策略为OR时, 请求头包含任意一header即可
                        return headers.stream().anyMatch(header -> existHeaderFunc.apply(httpHeaders,header));
                }
            }

            @Override
            public String toString() {
                return String.format("Config: %s", config.toString());
            }
        };
    }

    BiFunction<HttpHeaders, String, Boolean> existHeaderFunc = (httpHeaders, header) -> Optional.ofNullable(httpHeaders.get(header)).filter(list -> !list.isEmpty()).isPresent();

    public enum Strategy {
        AND, OR;
    }

    public static class Config {
        //配置的header, 可以配置多个
        private List<String> headers = new ArrayList<>();

        //当配置多个时,校验策略, and  还是 or
        private Strategy strategy = Strategy.OR;


        public List<String> getHeaders() {
            return headers;
        }

        public Strategy getStrategy() {
            return strategy;
        }

        public Config setHeaders(List<String> ignorePatterns) {
            this.headers = ignorePatterns;
            return this;
        }

        public void setStrategy(Strategy strategy) {
            this.strategy = strategy;
        }

        @Override
        public String toString() {
            return new ToStringCreator(this).append("headers", headers).append("strategy", strategy).toString();
        }
    }
}

configuration配置

    @Bean
    public HeaderTokenRoutePredicateFactory headerTokenRoutePredicateFactory() {
        return new HeaderTokenRoutePredicateFactory();
    }

yaml配置
配置predicate:类型为HeaderToken

spring:
  cloud:
    gateway:
      routes:
        - id: header_token_route
          uri: forward:///user/login
          predicates:
            - name: HeaderToken
              args:
              #   所有请求,只要请求头中包含username,password 
              ## 就 forward:///user/login
                headers: username,password
                strategy: AND

测试
访问一个不存在的地址/xyz测试:
在这里插入图片描述

自定义 Filter

PreLog
preLog 向请求头中添加属性,记录请求开始时间。

public class PreLogGatewayFilterFactory extends AbstractGatewayFilterFactory<PreLogGatewayFilterFactory.Config> implements Ordered {

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("level");
    }

    public static final String REQUEST_TIME_IN_KEY = "request_time_in";

    public PreLogGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                                     GatewayFilterChain chain) {
                //请求开始前记录时间
               if( config.getLevel() == Level.DEBUG) {
                   System.out.println("------------------------preLog开始处理请求....."+ LocalDateTime.now());
               }
//             无法直接操作 header,会抛出 ReadOnlyHttpHeaders.add xxx 异常
//             exchange.getRequest().getHeaders().add(REQUEST_TIME_IN_KEY,String.valueOf(System.currentTimeMillis()));

                ServerHttpRequest changedRequest = exchange.getRequest()
                                                .mutate()
                                                .header(REQUEST_TIME_IN_KEY,String.valueOf(System.currentTimeMillis()))
                                                .build();

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

            @Override
            public String toString() {
                return filterToStringCreator(
                        PreLogGatewayFilterFactory.this)
                        .append(config.getLevel())
                        .toString();
            }
        };
    }

    public enum Level {
        DEBUG, INFO;
    }

    public static class Config {

        private Level level =Level.DEBUG;

        public Level getLevel() {
            return level;
        }

        public Config setLevel(Level level) {
            this.level = level;
            return this;
        }
    }


    @Override
    public int getOrder() {
        return 100;
    }
}

PostLog
PostLog 计算整个请求耗时:

@Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange,
                                     GatewayFilterChain chain) {
                return chain.filter(exchange).then(Mono.fromRunnable(()-> {
                    Optional.ofNullable(exchange.getRequest().getHeaders().get(REQUEST_TIME_IN_KEY)).ifPresent(list ->{
                       Long startTime =  Long.parseLong(list.get(0));
                        if( config.getLevel() == Level.INFO) {
                            System.out.println("----------------------耗时::" + (System.currentTimeMillis() - startTime));
                        }
                    });
                }));
            }

            @Override
            public String toString() {
                return filterToStringCreator(
                        PostLogGatewayFilterFactory.this)
                        .append(config.getLevel())
                        .toString();
            }
        };
    }

configuration配置

    @Bean
    public PostLogGatewayFilterFactory postLogGatewayFilterFactory() {
        return new PostLogGatewayFilterFactory();
    }

    @Bean
    public PreLogGatewayFilterFactory PreLogGatewayFilterFactory() {
        return new PreLogGatewayFilterFactory();
    }


yaml配置

spring:
  cloud:
    gateway:
      routes:
        - id: header_token_route
          uri: forward:///user/login
          predicates:
            - name: HeaderToken
              args:
                headers: username,password
                strategy: AND
          filters:
            - name: PreLog
              args:
                level: DEBUG
            - PostLog=INFO

测试
请求完毕后,后台会记录请求耗时日志:
在这里插入图片描述

自定义 GlobalFilter

GlobalFilter 比较简单, 只需要实现GlobalFilter接口,并注入容器即可。

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //记录所有请求信息
        URI url = exchange.getRequest().getURI();
        System.out.println("----------["+ LocalDateTime.now() +"]处理请求:"+ url.getRawPath() );
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 10;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值