琪琪色原网站,琪琪色影院,琪琪色原网站影音先锋_是全亚洲更新最快

琪琪色原网站,琪琪色影院,琪琪色原网站影音先锋_是全亚洲更新最快:Spring Cloud Gateway 限流返回值问题

发布于 11/19 10:00
阅读 207
收藏 0

我是用Spring Cloud Gateway  RedisRateLimiter   限流,已经成功了,并且返回http 状态码是429 。但是我想统一处理友好的返回给前端,请问在哪里拦截这个429 的状态码,然后自己封装返回?

加载中
0

简单,照着RequestRateLimiterGatewayFilterFactory,写一个自定义如:CustomRequestRateLimiterGatewayFilterFactory,然后在apply最后用exchange.getResponse().writeWith(Mono.just(buffer));输出结果就行。代码示例:

package com.flying.fish.gateway.filter.factory;

import com.flying.fish.formwork.util.Constants;
import com.flying.fish.formwork.util.HttpResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
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 reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;

@Slf4j
@Component
public class CustomRequestRateLimiterGatewayFilterFactory extends AbstractGatewayFilterFactory<CustomRequestRateLimiterGatewayFilterFactory.Config> {

    public static final String KEY_RESOLVER_KEY = "keyResolver";

    private final RateLimiter defaultRateLimiter;
    private final KeyResolver defaultKeyResolver;

    public CustomRequestRateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter, @Qualifier("requestIdKeyResolver") KeyResolver defaultKeyResolver) {
        super(Config.class);
        this.defaultRateLimiter = defaultRateLimiter;
        this.defaultKeyResolver = defaultKeyResolver;
    }

    public KeyResolver getDefaultKeyResolver() {
        return defaultKeyResolver;
    }

    public RateLimiter getDefaultRateLimiter() {
        return defaultRateLimiter;
    }

    @SuppressWarnings("unchecked")
    @Override
    public GatewayFilter apply(Config config) {
        KeyResolver resolver = (config.keyResolver == null) ? defaultKeyResolver : config.keyResolver;
        RateLimiter<Object> limiter = (config.rateLimiter == null) ? defaultRateLimiter : config.rateLimiter;
        return (exchange, chain) -> {
            Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
            return resolver.resolve(exchange).flatMap(key ->
                    // TODO: if key is empty?
                    limiter.isAllowed(route.getId(), key).flatMap(response -> {
                        for (Map.Entry<String, String> header : response.getHeaders().entrySet()) {
                            exchange.getResponse().getHeaders().add(header.getKey(), header.getValue());
                        }
                        if (response.isAllowed()) {
                            return chain.filter(exchange);
                        }

                        ServerHttpResponse httpResponse = exchange.getResponse();
                        httpResponse.setStatusCode(config.getStatusCode());
                        httpResponse.getHeaders().add(Constants.CONTENT_TYPE, Constants.APPLICATION_JSON);
                        log.error("访问已限流,请稍候再请求");
                        DataBuffer buffer = httpResponse.bufferFactory().wrap("访问已限流,请稍候再请求".getBytes(StandardCharsets.UTF_8));
                        return httpResponse.writeWith(Mono.just(buffer));

                        //return HttpResponseUtils.writeUnauth(exchange.getResponse(), "网关转发客户端,执行验证异常:访问已限流,请稍候再请求");
                        //return httpResponse.setComplete();
                    }));
        };
    }

    public static class Config {
        private KeyResolver keyResolver;
        private RateLimiter rateLimiter;
        private HttpStatus statusCode = HttpStatus.TOO_MANY_REQUESTS;

        public KeyResolver getKeyResolver() {
            return keyResolver;
        }

        public Config setKeyResolver(KeyResolver keyResolver) {
            this.keyResolver = keyResolver;
            return this;
        }
        public RateLimiter getRateLimiter() {
            return rateLimiter;
        }

        public Config setRateLimiter(RateLimiter rateLimiter) {
            this.rateLimiter = rateLimiter;
            return this;
        }

        public HttpStatus getStatusCode() {
            return statusCode;
        }

        public Config setStatusCode(HttpStatus statusCode) {
            this.statusCode = statusCode;
            return this;
        }
    }
}

application.yml

# 略...
# 添加到 spring.cloud.gateway.routes 下
# 添加限流机器,基于令牌桶算法,当服务超出限流约束,则直接拒决请求:RequestRateLimiter(默认),CustomRequestRateLimiter(自定义)
        - name: CustomRequestRateLimiter
          args:
            key-resolver: '#{@uriKeyResolver}'
            redis-rate-limiter.replenishRate: 1
            redis-rate-limiter.burstCapacity: 1
# 略...

 

一局惊喜梦中人,谢谢
0

实现 ErrorWebExceptionHandler自己去响应异常

回复 : 我准备换种方式了,全局Response拦截,然后判断429,自己再输出
回复 : 这就很无奈了~
回复 : 看代码里它是在RequestRateLimiterGatewayFilterFactory过滤器里直接response响应的,没有抛出异常,确实捕获不到。将他这个过滤器重写了。
这种方案我试过,捕获不到 http 429 这个状态码
返回顶部
顶部