网关

概述

网关作用显著,它能作为统一入口,整合后端服务,让客户端无需多次请求。

  • 统一入口:整合后端多个服务,客户端只需调用网关提供的唯一接口,无需多次请求不同服务。
  • 统一鉴权:集中处理所有服务的身份认证与访问权限控制,无需各服务单独处理。
  • 服务发布控制:支持灰度发布等,能灵活控制流量分流到新旧服务,保障服务更新平稳。
  • 协议转换:统一处理后端不同协议,对外提供一致的 HTTP 协议接口,简化客户端适配。
  • 请求转发:接收客户端请求后,转发到对应的后端服务,还可实现内网与外网隔离。
  • 限流、缓存:对请求进行限流,防止系统过载;缓存常用数据,提升响应速度。

鉴权认证

服务发布

灰度发布:新服务上线时,在网关层利用分流引擎

蓝绿发布

将新版本和旧版本都进行部署,然后将新版本上线,利用分流将所有请求换到新版本v2,当出现故障时,直接切回v1即可。

A / B Test

【使用于**测试新系统是否受欢迎**,如果发现不受欢迎则不上新服务】

新服务上线后,设定规则,只有符合规则的才可以访问到新服务(比如设置请求头Header的方法使得安卓用户可访问其他不行)

金丝雀/灰度 发布

刚开始将少量的请求引流到新版本上,然后后续再逐渐引入更多流量

实战

1. 路由匹配规则

  • 时间匹配:通过<font style="color:rgb(0, 0, 0);">Before</font>/<font style="color:rgb(0, 0, 0);">After</font>谓词,根据时间范围转发请求(如指定时间前 / 后路由到特定服务)
  • Cookie 匹配<font style="color:rgb(0, 0, 0);">Cookie</font>谓词,根据请求中是否包含指定 Cookie 键值对进行路由
  • Header 匹配<font style="color:rgb(0, 0, 0);">Header</font>谓词,检查请求头中是否存在指定键及符合正则的 value(如<font style="color:rgb(0, 0, 0);">X-Request-Id</font>为数字)
  • Host 匹配<font style="color:rgb(0, 0, 0);">Host</font>谓词,根据请求头中的 Host 字段匹配(支持通配符,如<font style="color:rgb(0, 0, 0);">**.muse.com</font>
  • 请求方法匹配<font style="color:rgb(0, 0, 0);">Method</font>谓词,仅允许指定 HTTP 方法(如 POST)的请求通过
  • 路径匹配<font style="color:rgb(0, 0, 0);">Path</font>谓词,按 URL 路径匹配(支持通配符,如<font style="color:rgb(0, 0, 0);">/gateway/**</font>

2. 过滤器功能

  • 路径处理<font style="color:rgb(0, 0, 0);">StripPrefix</font>,转发前移除路径前缀(如<font style="color:rgb(0, 0, 0);">StripPrefix=1</font>移除第一个路径段)
  • 参数添加<font style="color:rgb(0, 0, 0);">AddRequestParameter</font>,为请求添加固定查询参数(如统一添加<font style="color:rgb(0, 0, 0);">teacher=muse</font>
  • 响应头处理<font style="color:rgb(0, 0, 0);">AddResponseHeader</font>,为响应添加固定 Header(如<font style="color:rgb(0, 0, 0);">X-Response-Teacher=Muse</font>
  • 限流控制<font style="color:rgb(0, 0, 0);">RequestRateLimiter</font>,基于令牌桶算法限制请求频率(<font style="color:rgb(0, 0, 0);">replenishRate</font>为令牌填充速度,<font style="color:rgb(0, 0, 0);">burstCapacity</font>为令牌桶容量)
  • 请求重试<font style="color:rgb(0, 0, 0);">Retry</font>,当后端返回指定状态码(如 500)时自动重试(<font style="color:rgb(0, 0, 0);">retries</font>为重试次数)
  • 指标监控<font style="color:rgb(0, 0, 0);">GatewayMetricsFilter</font>,通过配置 management 端点暴露网关监控指标
  • 自定义过滤:通过<font style="color:rgb(0, 0, 0);">name</font>指定自定义过滤器类(需遵循<font style="color:rgb(0, 0, 0);">XXXGatewayFilterFactory</font>命名规范),支持传入自定义参数
server:
  port: 8088
#  以下路由只能选一个

#【请求路径匹配路由】
# 请求POST http://localhost:8088/gateway/say会转发http://localhost:8080/say。
spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://localhost:8080 #访问地址
          predicates:
            - Path=/gateway/** # 路径匹配
          filters:
            - StripPrefix=1 # StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。
                            # 如果我们设置StripPrefix=2时,当通过网关向/gateway/bar/foo 发出请求时,对nameservice的请求将类似于/foo。

#【指定时间规则匹配路由】 
# 在2027-01-01 00:00:00之前访问的请求,都会转到http://localhost:8080,、
# 即:http://localhost:8088/say会转发到http://localhost:8080/say
spring:
  cloud:
    gateway:
      routes:
        - id: before_route
          uri: http://localhost:8080			 # 目标服务地址,请求最终转发的目的地
          predicates: 										 # 只有当请求满足该路由的所有谓词条件时,才会触发路由转发。
            - Before=2027-01-01T00:00:00.000+08:00 	# 即请求是符合再2027-01-01之前发送的,就符合该网关的转发,可以转发

#【指定时间规则匹配路由】
#在2021-01-01 00:00:00之后访问的请求,都会转到http://localhost:8080,即:http://localhost:8088/say会转发到http://localhost:8080/say
spring:
  cloud:
    gateway:
      routes:
        - id: after_route
          uri: http://localhost:8080
          predicates:
            - After=2021-01-01T00:00:00.000+08:00

#【指定Cookie规则匹配路由】
#请求配置localhost的Cookie(chocolate=mic;) 请求http://localhost:8088/say会转发到http://localhost:8080/say
spring:
  cloud:
    gateway:
      routes:
        - id: cookie_route
          uri: http://localhost:8080
          predicates:
            - Cookie=chocolate, mic # 即需要cookie中 chocolate = mic

#【指定Header规则匹配路由】
#请求配置Header(key=X-Request-Id value=1) 请求http://localhost:8088/say会转发到http://localhost:8080/say
spring:
  cloud:
    gateway:
      routes:
        - id: header_route
          uri: http://localhost:8080
          predicates:
            - Header=X-Request-Id, \d+

#【指定Host规则匹配路由】
#请求配置Header(Host:www.muse.com) 请求http://localhost:8088/say会转发到http://localhost:8080/say
spring:
  cloud:
    gateway:
      routes:
        - id: host_route
          uri: http://localhost:8080
          predicates:
            - Host=**.muse.com

#【请求方法匹配路由】
# 请求POST http://localhost:8088/shout会转发http://localhost:8080/shout。请求GET http://localhost:8088/say 会报"404 Not Found"
spring:
 cloud:
   gateway:
     routes:
       - id: method_route
         uri: http://localhost:8080 #访问地址
         predicates:
           - Method=POST

#【请求路径匹配路由】
# 请求POST http://localhost:8088/gateway/say会转发http://localhost:8080/say。
spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: http://localhost:8080 #访问地址
          predicates:
            - Path=/gateway/** #路径匹配
          filters:
            - StripPrefix=1 #StripPrefix参数表示在将请求发送到下游之前从请求中剥离的路径个数。如果我们设置StripPrefix=2时,当通过网关向/gateway/bar/foo
#  发出请求时,对nameservice的请求将类似于/foo。

#【添加request查询参数过滤器】
#会对所有请求增加teacher=muse这个参数
spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: http://localhost:8080 #访问地址
          predicates:
            - Path=/**
          filters:
            - AddRequestParameter=teacher, muse

#【添加response响应Header参数过滤器】
#返回结果给客户端之前,在Header中添加相应的数据
spring:
  cloud:
    gateway:
      routes:
        - id: add_response_header_route
          uri: http://localhost:8080 #访问地址
          predicates:
            - Path=/**
          filters:
            - AddResponseHeader=X-Response-Teacher, Muse

#【添加限流过滤器】
spring:
  cloud:
    gateway:
      routes:
        - id: request_ratelimiter_route
          uri: http://localhost:8080 #访问地址
          predicates:
            - Path=/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 1 #令牌桶中令牌的填充速度,代表允许每秒执行的请求数
                redis-rate-limiter.burstCapacity: 1 #令牌桶的容量,也就是令牌桶最多能够容纳的令牌数。表示每秒用户最大能够执行的请求数量
redis:
  host: 127.0.0.1
  port: 6379

#【添加请求重试过滤器】
spring:
  cloud:
    gateway:
      routes:
        - id: retry_route
          uri: http://localhost:8080
          predicates:
            - Path=/example/**
          filters:
            - name: Retry
              args:
                retries: 3 #请求重试次数,默认值是3
                status: 500 #HTTP请求返回的状态码,针对指定状态码进行重试。
            - StripPrefix=1

#【网关指标过滤器——GatewayMetricsFilter】
management:
  endpoint:
    gateway:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"


自定义过滤器

#【请求路径匹配路由——配置自定义过滤器】
spring:
  cloud:
    gateway:
      routes:
        - id: define_filter
          uri: http://localhost:8080 #访问地址
          predicates:
            - Path=/gateway/** #路径匹配
          filters:
            - name: GpDefine # 自定义过滤器的名字,即:GpDefineGatewayFilterFactory
              args:
                name: Gp_Mic #GpConfig.getName这个值
            - StripPrefix=1 #跳过前缀

自定义过滤器:类名必须命名为 xxGatewayFilterFactory

xx 即为 name,这个 name 需要到 yaml 中配置,该过滤器才会生效【如下面的GpDefine】

作用与使用场景:

  • 作用:仅对配置了该过滤器的路由生效,实现路由级别的个性化处理。
  • 使用场景
    • 特定路由的日志记录(如支付路由单独记录请求参数)。
    • 路由级别的参数校验(如仅对用户路由验证 token 格式)。
    • 路由专属的响应加工(如对商品路由的响应添加促销标签)。
package com.muse.gatewaysample;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

/**
 * 自定义路由级别GatewayFilter
 * 注意:
 * 1. 类名必须以GatewayFilterFactory结尾,前缀(GpDefine)作为过滤器在yaml中的引用名称
 * 2. 需继承AbstractGatewayFilterFactory,泛型指定配置类类型
 * 3. 通过@Service注解注册到Spring容器中
 */
@Service
public class GpDefineGatewayFilterFactory extends AbstractGatewayFilterFactory<GpDefineGatewayFilterFactory.GpConfig> {

    /**
     * 构造方法:必须调用父类构造器,传入配置类Class对象
     * 用于告诉父类当前过滤器使用哪个配置类解析yaml参数
     */
    public GpDefineGatewayFilterFactory() {
        super(GpConfig.class);
    }

    /**
     * 核心方法:实现过滤逻辑
     * @param config 配置类对象,包含从yaml中读取的参数
     * @return GatewayFilter 过滤器实例
     */
    @Override
    public GatewayFilter apply(GpConfig config) {
        // 返回一个GatewayFilter函数式接口实现
        return ((exchange, chain) -> {
            // 【前置过滤逻辑】:在请求转发到后端服务之前执行
            // exchange包含请求和响应对象,可获取/修改请求参数、头信息等
            System.out.println("GpDefineGatewayFilterFactory [Pre] Filter Request, config.getName() = " + config.getName());
            
            // 继续执行过滤器链,chain.filter(exchange)会将请求传递给下一个过滤器
            // then()方法中的逻辑会在后端服务响应后执行(后置处理)
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                // 【后置过滤逻辑】:在后端服务返回响应后、响应给客户端之前执行
                System.out.println("GpDefineGatewayFilterFactory [Post] Response Filter");
            }));
        });
    }

    /**
     * 自定义配置类:用于接收yaml中配置的过滤器参数
     * 配置类的属性会与yaml中args下的参数自动绑定
     */
    public static class GpConfig {
        // 示例参数:name
        private String name;
        
        // 必须提供getter和setter方法,否则无法完成参数绑定
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }
    }
}

全局过滤器(GpdefineFilter)

去实现了全局过滤器,每个请求都会经过这个,无需配置即可使用(使用场景)

特点(与自定义过滤器的核心区别)

  • 无需 YAML 配置:所有请求都会经过,不依赖路由配置。
  • 全局生效:无论匹配哪个路由,都会执行该过滤器。

作用与使用场景

  • 作用:对整个网关的所有请求 / 响应进行统一处理。
  • 使用场景
    • 全局鉴权(如验证所有请求的 token 是否存在)。
    • 全局限流(如限制所有请求的 QPS)。
    • 全局日志收集(记录所有请求的 URL、耗时等)。
    • 跨域处理(统一配置 CORS 规则)。
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component  // 注册到容器
public class GpDefineFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, org.springframework.cloud.gateway.filter.GatewayFilterChain chain) {
        // 前置处理:所有请求都会经过这里(如全局鉴权)
        System.out.println("GlobalFilter [Pre] 全局前置处理");
        
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // 后置处理:所有响应返回前都会经过这里(如全局响应日志)
            System.out.println("GlobalFilter [Post] 全局后置处理");
        }));
    }

    @Override
    public int getOrder() {
        return 0;  // 执行顺序(0优先于1)
    }
}

nacos集成gateway

作用和使用场景

Nacos 作为注册中心和配置中心,与 Gateway 集成的核心价值是 实现服务的动态发现、路由管理和配置动态更新,解决网关对后端服务的动态适配问题。
具体体现:

  1. 服务发现与动态路由:Gateway 通过 Nacos 自动感知后端服务(Provider)的注册、下线、地址变更,无需手动修改路由的 uri 配置。
  2. 负载均衡:结合 lb://服务名 路由格式,Gateway 可基于 Nacos 提供的服务列表实现请求的负载均衡(如轮询、权重等)。
  3. 配置动态刷新:若网关路由规则配置在 Nacos 配置中心,修改后可实时生效,无需重启网关服务。
使用场景
  1. 微服务架构中的服务路由:当系统存在多个后端服务(如用户服务、订单服务),且服务实例会动态扩缩容时,通过 Nacos 让 Gateway 自动发现服务并转发请求。
  2. 多环境适配:开发、测试、生产环境的服务地址不同,通过 Nacos 统一管理服务注册,Gateway 无需修改配置即可适配不同环境。
  3. 灰度发布 / 蓝绿部署:配合 Nacos 的权重配置,Gateway 可将部分流量路由到新版本服务实例,实现平滑更新。

需要nacos-gateway-provider(作为转发的地址)、nacos-gateway-consumer(作为直接地址)

1.consumer-yaml

server:
  port: 8888  # Consumer端端口(网关服务运行端口,客户端通过此端口访问网关)

spring:
  application:
    name: gateway-nacos-consumer  # 服务名(注册到Nacos的名称,用于标识网关服务)
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos注册中心地址(网关服务需注册到Nacos,才能发现Provider服务)
    gateway:
      discovery:
        locator:
          enabled: true  # 开启「从Nacos注册中心动态创建路由」的功能(无需手动配置每个Provider路由,可通过服务名访问)
          lower-case-service-id: true  # 允许使用小写的服务名访问(默认服务名是大写,开启后可通过 http://网关IP:端口/服务名/接口 访问)
      routes:  # 手动配置的路由规则(优先级高于动态路由)
        - id: gateway-nacos-provider  # 路由唯一标识(自定义,需唯一)
          uri: lb://gateway-nacos-provider  # 路由目标地址:lb=Load Balance(负载均衡),后面跟Provider在Nacos的服务名
          predicates:  # 路由匹配条件(满足才触发此路由)
            - Path=/nacos/**  # 路径匹配:客户端请求路径以 /nacos 开头时,触发此路由
          filters:  # 路由过滤器(对请求/响应做加工)
            - StripPrefix=1  # 移除路径前缀1级:如请求 /nacos/sayHello → 转发给Provider时路径变为 /sayHello

2.provider-yaml

server:
  port: 8080  # Provider端端口(业务服务运行端口,处理实际业务逻辑)

spring:
  application:
    name: gateway-nacos-provider  # 服务名(注册到Nacos的名称,Consumer端通过此名发现该服务)
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos注册中心地址(将Provider服务注册到Nacos,供网关发现)
package com.muse.gateway.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Provider端业务控制器:处理客户端通过网关转发过来的请求
 */
@RestController  // 标识此类为REST接口控制器(返回JSON数据,无页面)
public class NacosController {

    // 从配置文件中读取 server.port 属性值(即当前Provider服务的运行端口)
    @Value("${server.port}")
    private int port;

    /**
     * 业务接口:处理GET请求,返回带端口的问候信息
     * 访问路径:Provider端原生路径是 /sayHello,通过网关访问时需加前缀 /nacos(对应Consumer路由配置)
     */
    @GetMapping("/sayHello")  // 映射GET请求到 /sayHello 路径
    public String sayHello() {
        // 控制台打印日志(用于调试,确认请求到达Provider)
        System.out.println("[gateway-nacos-provider]: sayHello");
        // 返回响应结果(包含端口,方便区分多实例部署时的负载均衡效果)
        return "[gateway-nacos-provider]: sayHello port=" + port;
    }
}

Sentinel 集成 Gateway 实现

作用和使用场景
核心作用

Sentinel 作为流量治理工具,与 Gateway 集成的核心价值是 对网关层的请求进行流量控制、熔断降级和监控,保护后端服务不被流量冲击。
具体体现:

  1. 网关层限流:基于路由、路径、参数等维度限制 QPS(如限制 /api/order/** 路径每秒最多 100 个请求)。
  2. 熔断降级:当后端服务响应缓慢或异常时,Sentinel 可触发熔断,直接返回降级响应(如 “服务繁忙”),避免请求堆积拖垮服务。
  3. 流量监控:通过 Sentinel 控制台实时查看网关的请求量、限流次数、响应时间等指标,便于问题排查。
使用场景
  1. 高并发接口保护:针对秒杀、促销等场景的核心接口(如 /api/seckill/**),通过限流防止流量超过服务承载能力。
  2. 服务稳定性保障:当后端服务出现异常(如数据库超时),通过熔断机制快速失败,避免网关持续转发无效请求。
  3. 流量监控与告警:实时监控网关流量趋势,当请求量突增或限流频繁时,通过 Sentinel 告警及时介入处理。
#### 1. 项目结构说明 + **sentinel-gateway-provider**:业务服务(被网关转发的目标服务) + **sentinel-gateway-consumer**:网关服务(集成 Sentinel 实现限流、熔断等功能)

二、代码与配置

1. 公共依赖(两个服务都需要)

xml

<!-- pom.xml 核心依赖 -->
<dependencies>
    <!-- Spring Cloud Gateway -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!-- Nacos 服务发现(如需注册中心) -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!-- Sentinel 集成 Gateway -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    </dependency>
    <!-- Sentinel 核心包 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
</dependencies>
2. Provider 端(sentinel-gateway-provider,业务服务)
(1)application.yml 配置
server:
  port: 8080  # Provider服务端口

spring:
  application:
    name: sentinel-gateway-provider  # 服务名(注册到Nacos的标识)
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos注册中心地址(可选,不使用注册中心可删除)
(2)业务控制器(ProviderController.java)
package com.muse.sentinel.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Provider业务接口:处理网关转发的请求
 */
@RestController
public class ProviderController {

    // 注入当前服务端口,用于区分实例
    @Value("${server.port}")
    private int port;

    /**
     * 测试接口:返回带端口的响应
     */
    @GetMapping("/test")
    public String test() {
        System.out.println("Provider接收请求,端口:" + port);
        return "Provider响应 [port=" + port + "]";
    }
}
3. Consumer 端(sentinel-gateway-consumer,网关服务)
(1)application.yml 配置

yaml

server:
  port: 8888  # 网关服务端口(客户端访问入口)

spring:
  application:
    name: sentinel-gateway-consumer  # 网关服务名
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # Nacos地址(可选)
    gateway:
      routes:
        - id: provider_route  # 路由唯一标识
          uri: lb://sentinel-gateway-provider  # 转发目标(lb=负载均衡,服务名对应Provider)
          predicates:
            - Path=/api/**  # 匹配路径:客户端访问/api/** 时触发此路由
          filters:
            - StripPrefix=1  # 移除1级前缀:/api/test → 转发为/test
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080  # Sentinel控制台地址(需单独启动)
        port: 8719  # 本地与Sentinel控制台通信的端口(默认8719,如被占用自动+1)
      scg:
        fallback:
          mode: response  # 限流/熔断后的降级模式(response=返回固定响应)
          response-body: "请求过于频繁,请稍后再试!"  # 降级响应内容
(2)网关配置类(SentinelGatewayConfig.java)
package com.muse.sentinel.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashSet;
import java.util.Set;

/**
 * Sentinel网关配置:注册过滤器并初始化限流规则
 */
@Configuration
public class SentinelGatewayConfig {

    /**
     * 注册Sentinel全局过滤器:所有请求都会经过此过滤器,实现限流/熔断
     */
    @Bean
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    /**
     * 初始化Sentinel限流规则(也可通过Sentinel控制台动态配置)
     */
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        
        // 为路由id=provider_route设置限流规则
        rules.add(new GatewayFlowRule("provider_route")
                .setCount(2)  // 限流阈值:每秒最多2个请求
                .setIntervalSec(1)  // 统计时间窗口(秒)
        );
        
        // 将规则加载到Sentinel
        GatewayRuleManager.loadRules(rules);
    }
}
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐