一、为什么需要服务网关?
在微服务架构中,服务被拆分得越来越细,会面临以下问题:
- 客户端直接调用多个微服务,存在跨域、认证复杂、请求地址管理混乱等问题;
- 每个微服务需要重复实现认证、限流、日志等功能,代码冗余;
- 微服务地址动态变化,客户端无法感知;
服务网关 作为微服务架构的入口,承接所有前端请求,实现路由转发、统一认证、限流熔断、日志监控等能力,解决以上痛点。
二、Gateway 核心概念
2.1 核心组件
- Route(路由) :网关最核心的组件,由
ID + 目标URI + 断言 + 过滤器组成,满足断言条件则转发请求到目标服务; - Predicate(断言):判断请求是否符合路由规则(如路径、请求头、请求方式等);
- Filter(过滤器) :对请求 / 响应进行拦截处理(如添加请求头、参数、限流、日志等),分为
GatewayFilter(局部)和GlobalFilter(全局)。
2.2 工作流程
客户端请求 → 网关接收请求 → 断言匹配路由 → 执行过滤器链(前置) → 转发请求到目标服务 → 执行过滤器链(后置) → 返回响应给客户端
三、Gateway 实战:快速搭建
3.1 环境准备
- SpringBoot 2.3.x + SpringCloud Hoxton.SR9
- 注册中心:Nacos(与上文 Sentinel 环境保持一致)
3.2 创建 Gateway 工程
3.2.1 引入依赖(pom.xml)
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud_parent</artifactId>
<groupId>com.hg</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway_server</artifactId>
<dependencies>
<!-- 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>
</dependencies>
</project>
3.2.2 配置文件(application.yml)
yaml:
server:
port: 9527 # 网关端口
spring:
application:
name: gateway-server # 网关服务名
cloud:
# Nacos配置
nacos:
discovery:
server-addr: 192.168.209.129:8848 # 注册中心地址
# Gateway配置
gateway:
# 开启服务发现(基于服务名转发)
discovery:
locator:
enabled: true
lower-case-service-id: true # 服务名小写
# 路由规则
routes:
# 路由1:转发到消费者服务
- id: sentinel-consumer-route # 路由ID,唯一
uri: lb://sentinel-consumer # 目标服务(lb://表示负载均衡)
predicates:
- Path=/consumer/** # 路径匹配规则
filters:
- StripPrefix=1 # 去除路径前缀(/consumer/xxx → /xxx)
# 路由2:转发到提供者服务
- id: sentinel-provider-route
uri: lb://sentinel-provider
predicates:
- Path=/provider/**
- Method=GET # 仅GET请求匹配
filters:
- StripPrefix=1
3.2.3 启动类
java
package com.hg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
3.3 测试路由转发
- 启动 Nacos、sentinel-provider、sentinel-consumer、gateway-server;
- 访问网关地址:
http://127.0.0.1:9527/consumer/hello3;- 网关会将请求转发到
sentinel-consumer的/hello3接口;
- 网关会将请求转发到
- 访问:
http://127.0.0.1:9527/provider/getUserById/1;- 网关会将请求转发到
sentinel-provider的/getUserById/1接口。
- 网关会将请求转发到
四、Gateway 核心功能实战
4.1 断言(Predicate)高级用法
支持多种断言规则,示例:
yaml:
predicates:
- Path=/consumer/** # 路径断言
- Method=GET,POST # 请求方式断言
- Header=token, \d+ # 请求头断言(token值为数字)
- Query=id, \d+ # 请求参数断言(id值为数字)
- After=2024-01-01T00:00:00+08:00[Asia/Shanghai] # 时间断言(指定时间后)
4.2 过滤器(Filter)实战
4.2.1 局部过滤器(GatewayFilter)
示例:添加请求头、设置响应头
yaml:
filters:
- AddRequestHeader=X-Request-From, Gateway # 添加请求头
- AddResponseHeader=X-Response-From, Gateway # 添加响应头
- RequestRateLimiter=2, 5, #{@redisRateLimiter} # 限流(需结合Redis)
4.2.2 全局过滤器(GlobalFilter)
自定义全局过滤器,实现统一认证:
java
package com.hg.filter;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取请求参数中的token
String token = exchange.getRequest().getQueryParams().getFirst("token");
// 2. 认证逻辑
if (token == null || !token.equals("admin123")) {
// 认证失败,返回401
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// 3. 认证通过,继续执行
return chain.filter(exchange);
}
// 过滤器执行顺序(值越小越先执行)
@Override
public int getOrder() {
return 0;
}
}
4.3 整合 Sentinel 实现网关限流
4.3.1 配置限流规则(yml)
yaml:
spring:
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080 # Sentinel控制台地址
gateway:
enabled: true # 开启Gateway限流
routes:
- id: sentinel-consumer-route # 对应网关路由ID
resource-mode: URL # 按URL限流
4.3.2 控制台配置限流规则
- 访问 Sentinel 控制台(
http://localhost:8080); - 找到
gateway-server,点击【网关流控】; - 新增规则:
- 资源名:
sentinel-consumer-route(网关路由 ID); - 阈值类型:QPS;
- 单机阈值:5;
- 流控效果:快速失败;
- 资源名:
- 高并发访问
http://127.0.0.1:9527/consumer/hello3,触发限流。
五、Gateway 高级特性
5.1 跨域配置
yaml:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*" # 允许所有源
allowedMethods: # 允许的请求方式
- GET
- POST
- PUT
- DELETE
allowedHeaders: "*" # 允许所有请求头
allowCredentials: true # 允许携带Cookie
5.2 负载均衡
Gateway 默认整合 Ribbon,支持负载均衡:
uri: lb://sentinel-consumer中lb://表示基于服务名负载均衡;- 可通过 Ribbon 配置权重、重试等:
yaml:
ribbon:
ConnectTimeout: 5000 # 连接超时
ReadTimeout: 5000 # 读取超时
MaxAutoRetries: 1 # 重试次数
六、总结
服务网关 Gateway 作为微服务的 "入口管家",核心价值在于:
- 路由转发:统一入口,屏蔽后端服务地址;
- 统一管控:集中实现认证、限流、日志、跨域等;
- 非侵入式:无需修改微服务代码,降低耦合;
结合 Sentinel 可实现网关层限流,进一步保障微服务架构的稳定性。在实际项目中,建议根据业务场景合理设计路由规则、过滤器链,兼顾性能与安全性。
补充说明
- 上述代码与上文 Sentinel 教程的工程体系(
springcloud_parent、sentinel-provider、sentinel-consumer)完全兼容; - 若需完整运行,需保证 Nacos、Sentinel 控制台正常启动;
- 核心依赖版本需与 SpringCloud/SpringBoot 版本匹配,避免冲突。