Spring Cloud Gateway 网关
1. 网关概述
1.1 什么是网关

API网关为微服务架构的系统提供简单、有效且统一的API路由管理,作为系统的统一入口,提供内部服务的路由中转,给客户端提供统一的服务。网关可以实现与业务解耦的公共逻辑,主要功能包括:
- 认证鉴权:验证用户身份和权限
- 路由转发:将请求路由到相应的微服务
- 安全策略:实施安全防护措施
- 流量控制:限流、熔断、降级
- 监控日志:请求监控和日志记录
- 防刷防护:防止恶意请求
1.2 主流网关技术选型
2. Spring Cloud Gateway 简介
2.1 概述
Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,旨在取代Netflix Zuul。它基于WebFlux + Netty + Reactor实现,采用响应式编程模型,不能在传统的Servlet容器中工作,也不能构建成WAR包。
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
2.2 核心特性
- 基于Spring Framework 5,Project Reactor和Spring Boot 2.x
- 动态路由
- 断言和过滤器
- 集成Hystrix断路器
- 集成Spring Cloud DiscoveryClient
- 易于编写的断言和过滤器
- 请求限流
- 路径重写
3. 核心概念
3.1 路由(Route)
路由是网关的基本构建块,包含:
- ID:唯一标识符
- 目标URI:路由到的目标地址
- 断言集合:匹配请求的条件
- 过滤器集合:请求处理链
3.2 断言(Predicate)
断言是Java 8函数式断言,用于匹配HTTP请求中的任何内容(如请求头、参数等)。当断言匹配成功时,请求才会被路由到相应的目标地址。
3.3 过滤器(Filter)
Spring Cloud Gateway过滤器用于修改请求和响应:
- Gateway Filter:特定路由的过滤器
- Global Filter:全局应用的过滤器
- Pre Filter:代理请求前执行的逻辑
- Post Filter:代理请求后执行的逻辑
4. 工作原理
4.1 请求处理流程

- 客户端向SpringCloud Gateway发出请求,如果请求与网关程序定义的路由匹配,则该请求就会被发送到网关Web处理程序,此时处理程序运行特定的请求过滤器链。
- 过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求的前后执行逻辑。所有 pre过滤器逻辑先执行,然后执行代理请求;代理请求完成后,执行post过滤器逻辑。

5. 快速开始
5.1 项目配置
pom.xml依赖
<dependencies>
<!– 公共模块 –>
<dependency>
<groupId>com.example</groupId>
<artifactId>mall-common</artifactId>
<version>1.0</version>
</dependency>
<!– Lombok –>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!– 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>
</dependencies>
application.yml配置
spring:
application:
name: mall–gateway
# Nacos配置
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# Gateway配置
gateway:
routes:
# 订单服务路由
– id: order_route
uri: lb://mall–order
predicates:
– Path=/order/**
# 用户服务路由
– id: user_route
uri: lb://mall–user
predicates:
– Path=/api/user/**
filters:
– StripPrefix=1 # 去除一层路径
# WebFlux应用类型
main:
web-application-type: reactive
5.2 启动类
@SpringBootApplication
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class, args);
}
}
6. 路由器断言工厂配置
predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地。application.yml配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
官方文档:https://docs.spring.jo/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
6.1 路径匹配
predicates:
– Path=/order/**
– Path=/api/user/**
6.2 Header匹配
predicates:
– Path=/api/user/**
– Header=X–Request–Id, \\d+ # 请求头X-Request-Id值为数字
6.3 其他常用断言
- Method:请求方法匹配
- Query:请求参数匹配
- Cookie:Cookie匹配
- Host:主机名匹配
- Before/After/Between:时间窗口匹配
7. 过滤器工厂配置
GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

7.1 添加请求头
filters:
– AddRequestHeader=X–Request–Color, red
微服务端获取请求头
@GetMapping("/test")
public String testGateway(@RequestHeader("X-Request-Color") String color) {
log.info("获取请求头颜色: {}", color);
return "success";
}
7.2 添加请求参数
filters:
– AddRequestParameter=color, blue
7.3 自定义过滤器工厂
@Component
@Slf4j
public class CheckAuthGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
log.info("调用CheckAuthGatewayFilterFactory: {} = {}",
config.getName(), config.getValue());
return chain.filter(exchange);
};
}
}
配置使用
filters:
– CheckAuth=zs,男 # 自定义过滤器工厂,名称必须符合规范
8. 全局过滤器配置
8.1 自定义全局过滤器
@Component
@Slf4j
public class CheckAuthFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取Token
String token = exchange.getRequest().getHeaders().getFirst("token");
if (StringUtils.isEmpty(token)) {
log.warn("Token为空,拒绝访问");
return unauthorizedResponse(exchange);
}
// 2. 验证Token(实际项目中需要调用认证服务)
if (!validateToken(token)) {
return unauthorizedResponse(exchange);
}
// 3. Token验证通过,添加用户信息到请求头
UserInfo userInfo = parseToken(token);
ServerHttpRequest request = exchange.getRequest().mutate()
.header("username", userInfo.getUsername())
.header("userId", userInfo.getUserId())
.build();
return chain.filter(exchange.mutate().request(request).build());
}
@Override
public int getOrder() {
return 0;
}
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
String message = "{\\"code\\": 401, \\"message\\": \\"未授权访问\\"}";
DataBuffer buffer = response.bufferFactory().wrap(message.getBytes());
return response.writeWith(Mono.just(buffer));
}
}
9. 跨域配置
9.1 YAML配置方式
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "*"
allowed-methods:
– GET
– POST
– PUT
– DELETE
– OPTIONS
allowed-headers: "*"
allow-credentials: true
max-age: 3600
9.2 Java配置方式
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
10. 限流配置
10.1 常见限流算法
令牌桶算法

- 令牌以固定速率生成并存入桶中
- 请求需要消耗令牌才能被处理
- 桶满时多余令牌被丢弃
- 令牌不足时请求被缓存或拒绝
漏桶算法

- 请求以任意速率进入漏桶
- 漏桶以固定速率处理请求
- 桶满时新请求被丢弃
滑动窗口算法

- 将时间划分为多个窗口
- 统计窗口内的请求数量
- 超过阈值则拒绝请求
10.2 Gateway基于Redis + Lua限流实现
springcloud alibaba官方提供了RequestRateLimiter过滤器工厂,基于redis+lua脚本方式采用令牌桶算法实现了限流。
官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-requestratelimiter-gatewayfilter-factory

添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置限流
spring:
redis:
host: 192.168.10.60
port: 6379
database: 0
lettuce:
pool:
max-active: 200
max-idle: 100
min-idle: 10
cloud:
gateway:
routes:
– id: user_route
uri: lb://mall–user
predicates:
– Path=/api/user/**
filters:
– name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 # 每秒令牌生成数
redis-rate-limiter.burstCapacity: 2 # 令牌桶容量
key-resolver: "#{@pathKeyResolver}" # 限流Key解析器
配置Key解析器
@Configuration
public class RateLimiterConfig {
/**
* 按路径限流
*/
@Bean
public KeyResolver pathKeyResolver() {
return exchange ->
Mono.just(exchange.getRequest().getURI().getPath());
}
/**
* 按参数限流
*/
@Bean
public KeyResolver parameterKeyResolver() {
return exchange ->
Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
/**
* 按IP限流
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange ->
Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
}
测试:

11. 微服务鉴权集成
11.1 鉴权流程
客户端请求 → 网关 → 认证中心验证Token → 返回用户信息
→ 网关添加用户信息到请求头 → 转发到微服务 → 微服务从请求头获取用户信息

11.2 网关配置
免认证URL配置
mall:
gateway:
should-skip-urls:
– /oauth/**
– /sso/**
– /home/**
– /pms/**
配置类
@Data
@ConfigurationProperties(prefix = "mall.gateway")
public class NotAuthUrlProperties {
private Set<String> shouldSkipUrls = new LinkedHashSet<>();
}
认证过滤器
@Component
@Slf4j
@EnableConfigurationProperties(NotAuthUrlProperties.class)
public class AuthorizationFilter implements GlobalFilter, Ordered {
@Autowired
private NotAuthUrlProperties notAuthUrlProperties;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String currentUrl = exchange.getRequest().getURI().getPath();
// 1. 检查是否为免认证路径
if (shouldSkip(currentUrl)) {
log.info("跳过认证路径: {}", currentUrl);
return chain.filter(exchange);
}
log.info("需要认证路径: {}", currentUrl);
// 2. 获取并验证Token
String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isEmpty(authHeader)) {
log.warn("认证路径缺少Token");
return unauthorizedResponse(exchange);
}
// 3. 验证Token(实际调用认证服务)
UserInfo userInfo = validateToken(authHeader);
if (userInfo == null) {
return unauthorizedResponse(exchange);
}
// 4. 添加用户信息到请求头
ServerHttpRequest request = exchange.getRequest().mutate()
.header("username", userInfo.getUsername())
.header("userId", userInfo.getUserId())
.build();
return chain.filter(exchange.mutate().request(request).build());
}
private boolean shouldSkip(String currentUrl) {
PathMatcher pathMatcher = new AntPathMatcher();
return notAuthUrlProperties.getShouldSkipUrls().stream()
.anyMatch(pattern -> pathMatcher.match(pattern, currentUrl));
}
@Override
public int getOrder() {
return –1;
}
}
11.3 微服务端配置
用户信息DTO
@Data
public class UserInfoDto {
private String username;
private String userId;
private String role;
private String department;
}
ThreadLocal工具类
public class UserInfoHolder {
private static final ThreadLocal<UserInfoDto> USER_INFO = new ThreadLocal<>();
public static void setUserInfo(UserInfoDto userInfo) {
USER_INFO.set(userInfo);
}
public static UserInfoDto getUserInfo() {
return USER_INFO.get();
}
public static void clear() {
USER_INFO.remove();
}
}
拦截器
@Component
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 从请求头获取用户信息
String userId = request.getHeader("userId");
String username = request.getHeader("username");
if (StringUtils.isNotBlank(userId)) {
UserInfoDto userInfo = new UserInfoDto();
userInfo.setUserId(userId);
userInfo.setUsername(username);
UserInfoHolder.setUserInfo(userInfo);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
UserInfoHolder.clear();
}
}
拦截器注册
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/health", "/actuator/**");
}
}
12. 最佳实践
12.1 生产环境建议
12.2 性能优化
12.3 安全建议
13. 常见问题排查
13.1 启动问题
- 问题:启动失败,提示Servlet相关错误
- 解决:检查spring.main.web-application-type=reactive
13.2 路由失效
- 问题:配置的路由不生效
- 解决:检查路由ID唯一性,断言配置正确性
13.3 跨域问题
- 问题:浏览器提示跨域错误
- 解决:检查CORS配置,确保OPTIONS请求正确处理
13.4 限流异常
- 问题:限流配置不生效
- 解决:检查Redis连接,确认KeyResolver配置正确
网硕互联帮助中心




评论前必须登录!
注册