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

如何基于Zuul与Eureka实现按请求头路由至指定版本微服务实例

实现基于请求头Version的Zuul路由规则

这需求其实很典型,咱们可以通过自定义Zuul过滤器来实现——核心就是在路由阶段拦截请求,根据请求头里的version值,从Eureka注册中心的test服务实例中筛选出metadata-map.version匹配的实例,然后指定路由到该实例。下面给你一步步来:

步骤1:确保依赖配置正确

首先得保证你的项目已经引入了Zuul和Eureka Client的Spring Boot Starter依赖,比如Maven项目的pom.xml:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

步骤2:自定义Zuul路由过滤器

创建一个类继承ZuulFilter,注入DiscoveryClient来获取Eureka中的服务实例列表,在run()方法里实现版本匹配的核心逻辑:

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Optional;

@Component
public class VersionRouteFilter extends ZuulFilter {

    private final DiscoveryClient discoveryClient;

    // 构造注入DiscoveryClient
    public VersionRouteFilter(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }

    @Override
    public String filterType() {
        // 指定在路由阶段执行,对应Zuul的Route处理阶段
        return FilterConstants.ROUTE_TYPE;
    }

    @Override
    public int filterOrder() {
        // 设置执行顺序,比默认路由过滤器优先级更高(默认是10)
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        // 只对test服务的请求生效,且请求头携带version时才执行
        String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
        return "test".equals(serviceId) && StringUtils.hasText(request.getHeader("version"));
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String targetVersion = request.getHeader("version");

        // 从Eureka获取test服务的所有健康实例
        List<org.springframework.cloud.client.ServiceInstance> instances = discoveryClient.getInstances("test");
        if (instances.isEmpty()) {
            throw new ZuulException("No available test service instance", 503, "Service Unavailable");
        }

        // 筛选出metadata中version匹配的实例
        Optional<org.springframework.cloud.client.ServiceInstance> targetInstance = instances.stream()
                .filter(instance -> targetVersion.equals(instance.getMetadata().get("version")))
                .findFirst();

        if (targetInstance.isPresent()) {
            org.springframework.cloud.client.ServiceInstance instance = targetInstance.get();
            // 构造目标实例的访问地址,替换Zuul默认路由地址
            String targetUrl = String.format("http://%s:%d", instance.getHost(), instance.getPort());
            ctx.setRouteHost(java.net.URI.create(targetUrl));
        } else {
            // 无匹配实例时的降级处理
            ctx.setResponseStatusCode(404);
            ctx.setSendZuulResponse(false);
            ctx.setResponseBody(String.format("No test service instance with version %s found", targetVersion));
        }
        return null;
    }
}

步骤3:配置Zuul基础路由规则

在网关的application.yml里添加基础路由配置,把/test/**路径的请求映射到test服务:

spring:
  application:
    name: zuul-gateway
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/ # 替换成你的Eureka注册中心地址
zuul:
  routes:
    test:
      path: /test/**
      service-id: test

测试验证

  • 发送带version:1的请求:curl -H "version:1" http://localhost:网关端口/test/你的接口路径,会被路由到7878端口的实例
  • 发送带version:2的请求:curl -H "version:2" http://localhost:网关端口/test/你的接口路径,会被路由到7879端口的实例

额外说明

  • 如果请求头没带version,可以在shouldFilter()里返回false,让Zuul走默认的轮询路由;也可以在run()里加默认逻辑,比如路由到版本1的实例
  • DiscoveryClient默认只会返回健康的实例,不用担心路由到已下线的服务

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:07:29