You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway 2.0.0 M9响应缓存实现可行性咨询

嘿,针对你在Spring Cloud Gateway 2.0.0 M9中想要实现类似代理缓存的响应缓存需求(支持带参数的URL),我来分享下可行的方案——就像你用Hystrix实现熔断那样,我们可以通过自定义GatewayFilter来搞定这个需求:

核心思路

Spring Cloud Gateway本身并没有内置的代理缓存过滤器,但它的扩展机制允许我们自定义过滤器来实现缓存逻辑。我们可以借助Spring的Cache抽象层(支持Caffeine、Redis等多种缓存实现),将请求的「路径+有序参数」作为缓存Key,实现对带参数URL的差异化缓存。

具体实现步骤

1. 添加依赖

首先引入Spring Cache和缓存实现(这里以轻量的Caffeine为例):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

2. 自定义缓存过滤器工厂

我们需要实现一个GatewayFilterFactory,用来处理缓存的读取和写入逻辑:

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

@Component
public class CacheResponseGatewayFilterFactory extends AbstractGatewayFilterFactory<CacheResponseGatewayFilterFactory.Config> {

    private final CacheManager cacheManager;

    public CacheResponseGatewayFilterFactory(CacheManager cacheManager) {
        super(Config.class);
        this.cacheManager = cacheManager;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 生成缓存Key:路径+按Key排序的参数(避免参数顺序不同导致缓存Key不一致)
            String path = exchange.getRequest().getPath().toString();
            String queryParams = exchange.getRequest().getQueryParams().entrySet().stream()
                    .sorted(java.util.Map.Entry.comparingByKey())
                    .map(entry -> entry.getKey() + "=" + String.join(",", entry.getValue()))
                    .collect(Collectors.joining("&"));
            String cacheKey = path + (queryParams.isEmpty() ? "" : "?" + queryParams);

            Cache cache = cacheManager.getCache(config.getCacheName());
            if (cache != null) {
                // 尝试从缓存获取响应
                byte[] cachedResponse = cache.get(cacheKey, byte[].class);
                if (cachedResponse != null) {
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.OK);
                    response.getHeaders().add("X-Cache", "HIT");
                    return response.writeWith(Mono.just(response.bufferFactory().wrap(cachedResponse)));
                }
            }

            // 缓存未命中,继续执行路由,然后缓存成功的响应
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                exchange.getResponse().getBody().subscribe(buffer -> {
                    byte[] responseBytes = new byte[buffer.readableByteCount()];
                    buffer.read(responseBytes);
                    if (cache != null && exchange.getResponse().getStatusCode().is2xxSuccessful()) {
                        cache.put(cacheKey, responseBytes);
                        exchange.getResponse().getHeaders().add("X-Cache", "MISS");
                    }
                });
            }));
        };
    }

    // 配置类,用于指定缓存名称
    public static class Config {
        private String cacheName;

        public String getCacheName() {
            return cacheName;
        }

        public void setCacheName(String cacheName) {
            this.cacheName = cacheName;
        }
    }
}

3. 在路由中启用缓存过滤器

在你的RouteLocator配置里,添加自定义的缓存过滤器,就像配置Hystrix过滤器那样:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.TimeUnit;

@SpringBootApplication
@EnableCaching // 启用Spring Cache
public class WorkflowGatewayApiApplication {

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

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/api/**")
                        // 应用缓存过滤器,指定缓存名称
                        .filters(f -> f.filter(new CacheResponseGatewayFilterFactory(cacheManager()).apply(
                                config -> config.setCacheName("apiResponseCache"))))
                        .uri("http://your-backend-service")) // 替换成你的后端服务地址
                .build();
    }

    // 配置Caffeine缓存的过期策略和容量
    @Bean
    public CaffeineCacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("apiResponseCache");
        cacheManager.setCaffeine(Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES) // 缓存10分钟后过期
                .maximumSize(1000)); // 最多缓存1000条响应
        return cacheManager;
    }
}

关键注意事项

  • 参数排序处理:代码中对请求参数按Key排序后拼接,确保/api/data?id=1&name=foo和/api/data?name=foo&id=1会命中同一个缓存条目。
  • 缓存范围控制:只缓存2xx状态码的成功响应,避免缓存错误结果影响业务。
  • 缓存实现切换:如果需要分布式缓存,可以把CaffeineCacheManager换成RedisCacheManager,只需调整依赖和配置即可。
  • 响应体处理:因为Spring Cloud Gateway是基于Reactive的,所以用响应式的方式读取和写入缓存,避免阻塞。

这种自定义过滤器的方式和你用Hystrix实现熔断的思路一致,都是利用Gateway的扩展机制来增强功能,完全适配你当前使用的2.0.0 M9版本。

内容的提问来源于stack exchange,提问作者Esteban S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:03:39