前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >每天20分钟之spring-cloud-gateway基础四自定义过滤工厂

每天20分钟之spring-cloud-gateway基础四自定义过滤工厂

原创
作者头像
李子健
修改2022-08-21 22:20:14
4490
修改2022-08-21 22:20:14
举报
文章被收录于专栏:每日一善每日一善

过滤器工厂(修改请求)

AddRequestHeader过滤器工厂

代码语言:txt
复制
- AddRequestHeader=from,abc

RemoveRequestHeader过滤器工厂

代码语言:txt
复制
- RemoveRequestHeader=from2

SetStatus过滤器工厂

代码语言:txt
复制
- id: statusFilter
    uri: http://www.example.com/
    predicates:
    - Query=foo,b1
    filters:
    - SetStatus=401

RedirectTo过滤器工厂

代码语言:txt
复制
- id: redictFilter
    uri: http://www.example.com/
    predicates:
    - Query=foo,b2
    filters:
    - RedirectTo=302,http://weibo.com

自定义过滤器工厂

  • 自定义过滤器配置
代码语言:txt
复制
 - id: lb-info
    uri: lb://consul-server-producer
    predicates:
    - Path=/info/**
    filters:
    - RemoveRequestHeader=from2
    - AddRequestHeader=from,abc
    - name: Login
        args:
        checkLogin: true
  • 自定义过滤器代码@Slf4j
代码语言:txt
复制
@Component
public class LoginGatewayFilterFactory extends AbstractGatewayFilterFactory<LoginCfg> {


public LoginGatewayFilterFactory() {

    super(LoginCfg.class);

}

@Override
public GatewayFilter apply(LoginCfg loginCfg) {

    return (exchange, chain) -> {
        log.info("if us check login:"+ loginCfg.isCheckLogin());
        ServerHttpRequest request = exchange.getRequest().mutate()
                .build();
        if (loginCfg.isCheckLogin()) {
            log.info("do login checking.......");
        }
        return chain.filter(exchange.mutate().request(request).build());
    };
}
}

全局过滤器

image.png
image.png

自定义全局过滤器

代码语言:txt
复制
package cn.beckbi.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Mono;

/**
 * @program: spring-cloud
 * @description:
 * @author: bikang
 * @create: 2022-08-21 20:21
 */
@Slf4j
@Configuration
public class GlobalFilterConfig {


    @Bean
    @Order(-2)
    public GlobalFilter filter1() {
        return (exchange, chain) -> {
            log.info("filter1 pre");
            return chain.filter(
                    exchange
            ).then(
                Mono.fromRunnable(()->{
                    log.info("filter1 post");
                })
            );
        };
    }

    @Bean
    @Order(0)
    public GlobalFilter filter2() {
        return (exchange, chain) -> {
            log.info("filter2 pre");
            return chain.filter(
                    exchange
            ).then(
                    Mono.fromRunnable(()->{
                        log.info("filter2 post");
                    })
            );
        };
    }

    @Bean
    @Order(2)
    public GlobalFilter filter3() {
        return (exchange, chain) -> {
            log.info("filter3 pre");
            return chain.filter(
                    exchange
            ).then(
                    Mono.fromRunnable(()->{
                        log.info("filter3 post");
                    })
            );
        };
    }
}

自定义拦截器

代码语言:txt
复制
package cn.beckbi.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.loadbalancer.ResponseData;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;
import java.util.Objects;

/**
 * @program: spring-cloud
 * @description:
 * @author: bikang
 * @create: 2022-08-21 20:29
 */
@Slf4j
@Component
public class UserFilter implements GlobalFilter, Ordered {

    @Builder
    @Data
    static class Resp {
        private int code;
        private String msg;
    }

    private static final String BAD_CID = "123";

    private ObjectMapper mapper = new ObjectMapper();

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

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();

        boolean matchFilter = false;

        if (Objects.nonNull(queryParams) && Objects.nonNull(queryParams.get("cid"))) {
            String cid = queryParams.get("cid").get(0);
            if (Objects.nonNull(cid) && BAD_CID.equals(cid)) {
                matchFilter = true;
            }
        }






        if (matchFilter) {
            ServerHttpResponse serverHttpResponse = exchange.getResponse();
            Resp resp = Resp.builder()
                    .code(401)
                    .msg("非法请求")
                    .build();
            DataBuffer dataBuffer = serverHttpResponse.bufferFactory().wrap(
                    this.getJsonBytes(resp)
            );
            serverHttpResponse.setStatusCode(HttpStatus.UNAUTHORIZED);
            serverHttpResponse.getHeaders().add("Content-Type", "application/json; charset=utf-8");


            return serverHttpResponse.writeWith(Mono.just(dataBuffer));
        }

        return chain.filter(exchange);
    }

    private byte[] getJsonBytes(Object o) {
        try {
            return mapper.writeValueAsBytes(o);
        }catch (JsonProcessingException e) {
            log.error("json error", e);
        }
        return "".getBytes();
    }


}

http://127.0.0.1:10011/info/1231212312?cid=123

限流器代码:基于redis做限流

代码语言:txt
复制
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
代码语言:txt
复制
package cn.beckbi.limiter;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import reactor.core.publisher.Mono;

import java.util.Objects;

/**
 * @program: spring-cloud
 * @description:
 * @author: bikang
 * @create: 2022-08-21 21:02
 */
@Configuration
public class LimiterConfig {

    @Bean("ipKeyResolver")
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
                Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostName()
        );
    }

    @Bean("cidKeyResolver")
    public KeyResolver cidKeyResolver() {
        return exchange -> Mono.just(
                Objects.requireNonNull(exchange.getRequest().getQueryParams().getFirst("cid"))
        );
    }

    @Primary
    @Bean("apiKeyResolver")
    public KeyResolver apiKeyResolver() {
        return exchange -> {
            Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
            return Mono.just(
                    route.getId()+"#"+exchange.getRequest().getPath().value()
            );
        };
    }
}

限流器配置

代码语言:txt
复制
- name: RequestRateLimiter
    args:
    redis-rate-limiter.replenishRate: 1
    redis-rate-limiter.burstCapacity: 2
    key-resolver: "#{@apiKeyResolver}"

全局路由处理器

代码语言:txt
复制
package cn.beckbi.errorhandler;



import cn.beckbi.util.JsonUtil;
import lombok.Builder;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.util.annotation.Nullable;


/**
 * @program: spring-cloud
 * @description:
 * @author: bikang
 * @create: 2022-08-21 21:36
 */
@Component
@Slf4j
@Order(-1)
public class JsonHandler implements ErrorWebExceptionHandler {

    @Builder
    @Data
    static class Msg {
        int code;
        String msg;
    }
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {

        ServerHttpResponse response = exchange.getResponse();

        if (response.isCommitted()) {
            return Mono.error(ex);
        }

        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);


        ServerHttpRequest request = exchange.getRequest();
        String rawQuery = request.getURI().getRawQuery();
        String query = StringUtils.hasText(rawQuery) ? "?" + rawQuery : "";
        String path = request.getPath() + query ;
        String message ;
        HttpStatus status = null;
        if (ex instanceof ResponseStatusException) {
            status = ((ResponseStatusException) ex).getStatus();
        }

        if (status == null){
            status = HttpStatus.INTERNAL_SERVER_ERROR;
        }

        // 通过状态码自定义异常信息
        if (status.value() >= 400 && status.value() < 500){
            message = "路由服务不可达或禁止访问!";
        }else {
            message = "路由服务异常!";
        }
        message += " path:" + path;

        Msg msg = Msg.builder().code(status.value())
                .msg(message)
                .build();


        return response
                .writeWith(Mono.fromSupplier(() -> {
                    DataBufferFactory bufferFactory = response.bufferFactory();
                    return bufferFactory.wrap(JsonUtil.getJsonBytes(msg));
                }));
    }

}

代码路径: https://github.com/beckbikang/spring-cloud/tree/main/kgateway

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 过滤器工厂(修改请求)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档