乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • 学习路径
  • 第1章 微服务与 Spring Cloud 概述

    • 微服务与 Spring Cloud 概述
  • 第2章 服务注册与发现

    • Eureka 服务注册与发现
    • Consul 服务注册与发现
  • 第3章 客户端负载均衡

    • Ribbon 客户端负载均衡
    • Spring Cloud LoadBalancer
  • 第4章 声明式服务调用

    • Feign 声明式 HTTP 客户端
    • OpenFeign 高级特性与 Spring Cloud 集成
  • 第5章 服务容错与熔断

    • Resilience4j 服务容错与熔断
    • Sentinel 流量控制与熔断降级
  • 第6章 配置中心

    • Spring Cloud Config 配置中心
  • 第7章 API 网关

    • Spring Cloud Gateway 现代化 API 网关
    • Zuul 网关(已进入维护模式)
  • 第8章 消息驱动的微服务

    • Spring Cloud Stream 消息驱动的微服务
  • 第9章 分布式追踪与监控

    • Sleuth + Zipkin 分布式链路追踪
  • 第10章 最佳实践与面试考点

    • Spring Cloud 最佳实践与面试考点

Zuul 网关(已进入维护模式)

导学

"白歌,前端同学快疯了。"黄俪指着屏幕说,"我们的前端要调 8 个微服务的接口,每个服务的域名都不一样。而且在浏览器里跨域请求全被 CORS 拦了。"

白歌看了一眼架构图:"我们需要一个 API 网关,作为所有微服务对外的统一入口。Netflix Zuul 是上一代方案,虽然已进入维护模式,但理解它的设计思想对掌握 Gateway 很有帮助。"


定位与问题场景

API 网关在微服务架构中的角色:

网关解决的六大问题:

问题网关方案
入口分散统一入口,单一域名
跨域(CORS)网关统一处理 CORS
认证鉴权网关层统一校验 Token
限流网关前置限流,保护后端
协议转换HTTP → gRPC / WebSocket
日志审计统一记录所有 API 调用

Zuul 1.x 核心原理

Zuul 1.x 基于 Servlet 2.5 阻塞模型,使用 ZuulFilter 过滤器链处理请求:

Filter 分类:

类型执行时机典型用途
pre路由之前认证鉴权、限流、参数校验、请求日志
route路由之时转发请求到后端服务
post路由之后添加响应头、记录响应日志
error发生错误时错误处理、异常格式统一

完整示例:飞翔科技 Zuul 网关

依赖

<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>

启动类

@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ZuulGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }
}

路由配置

spring:
  application:
    name: feixiang-api-gateway

zuul:
  routes:
    # 方案一:服务名路由(推荐)
    order-service:
      path: /api/order/**
      serviceId: FEIXIANG-ORDER-SERVICE
      stripPrefix: true       # 转发时去掉 /api/order 前缀

    inventory-service:
      path: /api/inventory/**
      serviceId: FEIXIANG-INVENTORY-SERVICE

    # 方案二:URL 路由(不走 Eureka)
    payment-service:
      path: /api/payment/**
      url: http://localhost:9001

路由效果:

客户端请求:GET /api/inventory/1001
↓ stripPrefix=true
实际转发:GET /inventory/1001 → 库存服务

自定义 Filter——Token 认证

@Component
public class AuthFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre";   // Pre Filter
    }

    @Override
    public int filterOrder() {
        return 0;       // 最高优先级
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String path = ctx.getRequest().getRequestURI();
        // 排除登录接口
        return !path.startsWith("/api/auth/login");
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("{\"code\":401,\"message\":\"未授权\"}");
            ctx.getResponse().setContentType("application/json");
        }
        // 将 Token 中的用户 ID 传递给下游
        Long userId = parseUserId(token);
        ctx.addZuulRequestHeader("X-User-Id", String.valueOf(userId));

        return null;
    }
}

自定义 Filter——API 日志审计

@Component
public class ApiLogFilter extends ZuulFilter {
    @Override
    public String filterType() { return "post"; }

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

    @Override
    public boolean shouldFilter() { return true; }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        
        log.info("API 调用:{} {} → {},耗时:{}ms",
            request.getMethod(),
            request.getRequestURI(),
            ctx.getResponseStatusCode(),
            System.currentTimeMillis() - (Long) ctx.get("startTime")
        );
        return null;
    }
}

Zuul 2.x 与 Zuul 1.x 的区别

维度Zuul 1.xZuul 2.x
I/O 模型Servlet 阻塞Netty 异步非阻塞
线程模型每连接一线程Event Loop 事件驱动
推送支持不支持支持 WebSocket / Server-Sent Events
Spring 集成成熟不成熟
当前状态维护模式Netflix 内部使用,未广泛推广

Spring Cloud 官方推荐不要投入 Zuul 2.x,直接迁移到 Spring Cloud Gateway。


易错场景

1. 路由配置中 path 和 serviceId 不匹配导致 404

# ❌ 错误:path 和实际接口不符
inventory-service:
  path: /api/inventory/**
  serviceId: FEIXIANG-INVENTORY-SERVICE
# 客户端请求 /api/stock/1001 → 404

2. stripPrefix 设置为 false 导致后端 404

# 若 stripPrefix=false
# 客户端请求 /api/inventory/1001
# 实际转发:/api/inventory/1001 → 库存服务
# 但库存服务只有 /inventory/{productId} 接口 → 404

3. 敏感 Header 未传递

Zuul 默认过滤 Cookie、Set-Cookie、Authorization 三个敏感 Header。若有特殊需求需配置:

zuul:
  sensitive-headers:        # 清空敏感头列表
  routes:
    auth-service:
      sensitive-headers:    # 仅该路由不传递 Authorization

4. Zuul 1.x 的阻塞模型导致长连接饿死线程

Zuul 1.x 基于 Servlet,每个请求占用一个 Tomcat 工作线程。如果后端服务响应慢(如 5 秒),线程被长时间占用,高并发下线程池很快耗尽。这是 Zuul 1.x 的核心缺陷,也是 Gateway 诞生的原因。


面试考点

Zuul 1.x 和 Spring Cloud Gateway 的区别?

Zuul 1.x 基于 Servlet 2.5 阻塞模型,每个请求一个线程,不支持 WebSocket。Gateway 基于 Spring WebFlux 和 Reactor 异步非阻塞模型,Event Loop + 少量线程处理大量并发,支持长连接。Gateway 的路由匹配(Predicate)和过滤器(Filter)机制比 ZuulFilter 更灵活。Zuul 1.x 已进入维护模式,新项目应使用 Gateway。

Zuul 的生命周期过滤器有哪些?

pre(路由前:认证/限流)、route(路由时:转发请求)、post(路由后:处理响应/日志)、error(异常时:统一错误格式)。四类过滤器按 filterOrder 排序执行,同类型内数字越小越先执行。

Zuul 与 Nginx 的分工?

Nginx 负责最前端的流量接入(静态资源、SSL 卸载、IP 黑白名单),Zuul/Gateway 负责业务层的 API 治理(认证、限流、路由、日志)。典型架构:CDN → Nginx → API 网关 → 微服务。Nginx 偏运维层面,Zuul/Gateway 偏应用层面。


小结

Zuul 开创了 Java 侧 API 网关的先河,通过过滤器链机制提供路由、认证、限流等能力。但 Servlet 阻塞模型导致它在高并发 WebSocket 场景下力不从心。Spring Cloud Gateway 以响应式架构解决了这些问题——这正是下一节的内容。

上一页
Spring Cloud Gateway 现代化 API 网关