Skip to content
进阶

一句话答案

方式一:自定义 GlobalFilter(全局过滤器)

核心要点

方式一:自定义 GlobalFilter(全局过滤器)

最常见的场景:统一认证、日志记录。

java
@Component
@Order(-1)  // 数值越小,优先级越高
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // ========== Pre Filter 逻辑(请求到达下游之前) ==========
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst("Authorization");

        // 白名单路径放行
        String path = request.getURI().getPath();
        if (path.startsWith("/api/auth/login")) {
            return chain.filter(exchange);
        }

        // Token 校验
        if (token == null || !token.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        try {
            Claims claims = JwtUtil.parseToken(token.substring(7));
            // 将用户信息放入请求头,传递给下游服务
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", claims.getSubject())
                .header("X-User-Role", claims.get("role", String.class))
                .build();
            return chain.filter(exchange.mutate().request(mutatedRequest).build())
                .then(Mono.fromRunnable(() -> {
                    // ========== Post Filter 逻辑(下游响应返回之后) ==========
                    ServerHttpResponse response = exchange.getResponse();
                    log.info("请求完成: {} {} → {}", request.getMethod(),
                        path, response.getStatusCode());
                }));
        } catch (Exception e) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

方式二:自定义 GatewayFilter(局部过滤器)

java
// 自定义过滤器工厂
@Component
public class RequestTimingGatewayFilterFactory 
    extends AbstractGatewayFilterFactory<RequestTimingGatewayFilterFactory.Config> {

    public RequestTimingGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            long startTime = System.currentTimeMillis();
            exchange.getAttributes().put("startTime", startTime);

            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                long duration = System.currentTimeMillis() - startTime;
                if (duration > config.getSlowThreshold()) {
                    log.warn("慢请求: {} 耗时 {}ms", 
                        exchange.getRequest().getURI(), duration);
                }
            }));
        };
    }

    @Data
    public static class Config {
        private long slowThreshold = 1000; // 默认 1 秒
    }
}
yaml
# 在路由配置中使用
filters:
  - name: RequestTiming
    args:
      slowThreshold: 2000

Pre / Post 过滤器执行顺序示意:

请求 → [Global Pre -1] → [Global Pre 0] → [Route Pre 1]
     → 转发到下游服务 →
响应 ← [Route Post 1] ← [Global Post 0] ← [Global Post -1]

三、负载均衡与通信

追问与易错

追问方向:

  • Gateway 和 Zuul 区别?
  • Gateway 限流怎么做?
  • Gateway 怎么实现灰度?

易错点:

  • ❌ Gateway 和 Nginx 一样——职责不同
  • ❌ Gateway 性能不如 Nginx——职责不同不可比

💡 记忆锚点

Gateway像小区门卫:所有请求先过门卫(网关),门卫负责查身份证(认证GlobalFilter)、记出入登记(日志)、控制人流(限流)。过滤器链分Pre(请求到达前处理)和Post(响应返回后处理),GlobalFilter全局生效,GatewayFilter局部路由生效,Order值越小优先级越高。