Spring Cloud Gateway过滤器配置
往期回顾
Nacos的安装与配置
Spring Cloud集成Nacos作为注册中心
LoadBalacer集成Nacos实现负载均衡
常见的负载均衡策略分析
Spring Cloud集成Dubbo实现RPC调用
SpringCloud集成Nacos作为配置中心
Nacos整合OpenFegin实现RPC调用
Nacos整合Gateway入门实例
前面我们已经介绍了Nacos 的安装与配置,Spring Cloud 集成Nacos 作为服务的注册中心和配置中心,集成Nacos 实现服务的负载均衡和一些常见的负载均衡策略、使用Dubbo、OpenFegin进行RPC调用以及整合Spring Cloud Gateway作为服务的网关
在Nacos整合Gateway入门实例中,我们只是简单的介绍了如何集成Spring Cloud Gateway ,下面我们来详细说说Spring Cloud Gateway 的一些特性
Spring Cloud Gateway 建立在 Spring Boot 2.x、Spring WebFlux 和 Project Reactor 之上。 因此,当您使用 Spring Cloud Gateway 时,您所知道的许多熟悉的同步库(例如 Spring Data 和 Spring Security)和模式可能并不适用。 如果您不熟悉这些项目,我们建议您在使用 Spring Cloud Gateway 之前先阅读他们的文档以熟悉一些新概念。
Spring Cloud Gateway官网
路由的配置方式
基于配制文件
Spring Cloud Gateway 有两种配置路由和过滤器的方法:快捷方式和完全扩展的参数。下面的大多数示例都使用快捷方式。
快捷方式配置
快捷方式配置由过滤器名称识别,后跟等号 ( =),后跟以逗号 ( ,) 分隔的参数值。
spring:cloud:gateway:routes:- id: after_route #路由的ID,保证全局唯一就行了,建议和服务名搭配命名uri: https://example.org #uri,断言匹配时转发的uripredicates:- Cookie=mycookie,mycookievalue #断言,当断言匹配时就会转发至uri
完全扩展的参数
完全扩展的参数看起来更像是带有名称/值对的标准 yaml 配置。通常,会有一把name钥匙和一把args钥匙。键是用于配置谓词或过滤器的args键值对映射。
spring:cloud:gateway:routes:- id: after_route #路由的ID,保证全局唯一就行了,建议和服务名搭配命名uri: https://example.org #uri,断言匹配时转发的uripredicates:- name: Cookieargs:name: mycookieregexp: mycookievalue
之前我们项目中用到的路由匹配规则就是快捷方式
service-url:user-service: http://localhost:8080spring:cloud:gateway:# 静态路由 routes:- id: path_routeuri: ${service-url.user-service}/user/get/{id}predicates:- Path=/user/get/{id}
这个配置的意思就是当请求的URI 与/user/get/{id} 相匹配时,就会将请求转发至http://localhost:8080/user/get/{id}
基于Java代码的配置方式
除了可以通过配制文件的方式,我们还可以通过Java代码进行硬编码,但是我个人不推荐这种方式,因为一是我认为在配制文件中配置路由可读性更高,另外就是配制文件可以整合配置中心实现动态路由,而显然,Java硬编码的方式是没法配合配置中心进行动态路由的,灵活性不高
// Spring 官方的例子
@SpringBootApplication
public class DemogatewayApplication {@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes().route("path_route", r -> r.path("/get").uri("http://httpbin.org")).route("host_route", r -> r.host("*.myhost.org").uri("http://httpbin.org")).route("rewrite_route", r -> r.host("*.rewrite.org").filters(f -> f.rewritePath("/foo/(?.*)" , "/${segment}")).uri("http://httpbin.org")).route("hystrix_route", r -> r.host("*.hystrix.org").filters(f -> f.hystrix(c -> c.setName("slowcmd"))).uri("http://httpbin.org")).route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org").filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback"))).uri("http://httpbin.org")).route("limit_route", r -> r.host("*.limited.org").and().path("/anything/**").filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter()))).uri("http://httpbin.org")).build();}
}
网上Copy的代码
package com.atguigu.springcloud.config;import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author LiFang* @version 1.0* @since 2021/12/30 21:02* 使用java配置路由*/@Configuration
public class GateWayConfig {/*** @param routeLocatorBuilder* @return org.springframework.cloud.gateway.route.RouteLocator* @description 配置了一个id为route_name的路由规则,* 当访问地址为http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei* @author LiFang* @date 2021/12/30 21:27*/@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();routes.route("path_route_atguigu",r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();return routes.build();}@Beanpublic RouteLocator customRouteLocator2(RouteLocatorBuilder builder) {RouteLocatorBuilder.Builder routes = builder.routes();routes.route("path_route_atguigu2", r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build();return routes.build();}
}
过滤器
Route Predicate 的使用
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。 Spring Cloud Gateway包括许多内置的Route Predicate工厂。 所有这些Predicate都与HTTP请求的不同属性匹配。 多个Route Predicate工厂可以进行组合,下面我们来介绍下一些常用的Route Predicate。
注意:Predicate中提到的配置都在application-predicate.yml文件中进行修改,并用该配置启动api-gateway服务。
Spring Cloud Gateway自带了很多断言过滤器,可以让我们在断言中使用,我这里只简单的列举几个常用的,想要详细了解的可以查阅官方文档
After Route Predicate
在指定时间之后的请求会匹配该路由。
spring:cloud:gateway:routes:- id: after_routeuri: ${service-url.user-service}predicates:- After=2019-09-24T16:30:00+08:00[Asia/Shanghai]
Before Route Predicate
在指定时间之前的请求会匹配该路由。
spring:cloud:gateway:routes:- id: before_routeuri: ${service-url.user-service}predicates:- Before=2019-09-24T16:30:00+08:00[Asia/Shanghai]
Between Route Predicate
在指定时间区间内的请求会匹配该路由。
spring:cloud:gateway:routes:- id: before_routeuri: ${service-url.user-service}predicates:- Between=2019-09-24T16:30:00+08:00[Asia/Shanghai], 2019-09-25T16:30:00+08:00[Asia/Shanghai]
Cookie Route Predicate
带有指定Cookie的请求会匹配该路由
spring:cloud:gateway:routes:- id: cookie_routeuri: ${service-url.user-service}predicates:- Cookie=username,macro
带有cookie为username=macro的请求可以匹配该路由
Header Route Predicate
带有指定请求头的请求会匹配该路由
spring:cloud:gateway:routes:- id: header_routeuri: ${service-url.user-service}predicates:- Header=X-Request-Id, \d+
带有请求头为X-Request-Id:123的请求可以匹配该路由
Method Route Predicate
发送指定方法的请求会匹配该路由
spring:cloud:gateway:routes:- id: method_routeuri: ${service-url.user-service}predicates:- Method=GET
GET请求可以匹配该路由
Path Route Predicate
发送指定路径的请求会匹配该路由
spring:cloud:gateway:routes:- id: path_routeuri: ${service-url.user-service}/user/{id}predicates:- Path=/user/{id}
Query Route Predicate
带指定查询参数的请求可以匹配该路由
spring:cloud:gateway:routes:- id: query_routeuri: ${service-url.user-service}/user/getByUsernamepredicates:- Query=username
带username=macro查询参数的请求可以匹配该路由。
RemoteAddr Route Predicate
从指定远程地址发起的请求可以匹配该路由
spring:cloud:gateway:routes:- id: remoteaddr_routeuri: ${service-url.user-service}predicates:- RemoteAddr=192.168.1.1/24
从192.168.1.1发起请求可以匹配该路由
Weight Route Predicate
使用权重来路由相应请求,以下表示有80%的请求会被路由到localhost:8201,20%会被路由到localhost:8202
spring:cloud:gateway:routes:- id: weight_highuri: http://localhost:8201predicates:- Weight=group1, 8- id: weight_lowuri: http://localhost:8202predicates:- Weight=group1, 2
Route Filter 的使用
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生,下面我们介绍下常用路由过滤器的用法。
AddRequestHeader
AddRequestHeader GatewayFilter 采用名称和值参数。 以下示例配置一个 AddRequestHeader GatewayFilter:
spring:cloud:gateway:routes:- id: add_request_header_routeuri: https://example.orgfilters:- AddRequestHeader=X-Request-red, blue
这个例子将 X-Request-red:blue 标头添加到所有匹配请求的下游请求标头中
AddRequestParameter GatewayFilter
给请求添加参数的过滤器
spring:cloud:gateway:routes:- id: add_request_parameter_routeuri: http://localhost:8201filters:- AddRequestParameter=username, macropredicates:- Method=GET
以上配置会对GET请求添加username=macro的请求参数,相当于发起该请求:
curl http://localhost:8201/user/getByUsername?username=macro
StripPrefix GatewayFilter
对指定数量的路径前缀进行去除的过滤器
spring:cloud:gateway:routes:- id: strip_prefix_routeuri: http://localhost:8201predicates:- Path=/user-service/**filters:- StripPrefix=2
以上配置会把以/user-service/开头的请求的路径去除两位,通过curl工具使用以下命令进行测试
curl http://localhost:9201/user-service/a/user/1
相当于发起该请求:
curl http://localhost:8201/user/1
PrefixPath GatewayFilter
与StripPrefix过滤器恰好相反,会对原有路径进行增加操作的过滤器。
spring:cloud:gateway:routes:- id: prefix_path_routeuri: http://localhost:8201predicates:- Method=GETfilters:- PrefixPath=/user
以上配置会对所有GET请求添加/user路径前缀,通过curl工具使用以下命令进行测试。
curl http://localhost:9201/1
相当于发起该请求:
curl http://localhost:8201/user/1
Hystrix GatewayFilter
Hystrix 过滤器允许你将断路器功能添加到网关路由中,使你的服务免受级联故障的影响,并提供服务降级处理。
- 要开启断路器功能,我们需要在pom.xml中添加Hystrix的相关依赖:
<dependency><groupId>org.springframework.cloudgroupId><artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
- 然后添加相关服务降级的处理类:
@RestController
public class FallbackController {@GetMapping("/fallback")public Object fallback() {Map<String,Object> result = new HashMap<>();result.put("data",null);result.put("message","Get request fallback!");result.put("code",500);return result;}
}
- 在application-filter.yml中添加相关配置,当路由出错时会转发到服务降级处理的控制器上:
spring:cloud:gateway:routes:- id: hystrix_routeuri: http://localhost:8201predicates:- Method=GETfilters:- name: Hystrixargs:name: fallbackcmdfallbackUri: forward:/fallback
- 关闭user-service,调用该地址进行测试:http://localhost:9201/user/1 ,发现已经返回了服务降级的处理信息。

RequestRateLimiter GatewayFilter
RequestRateLimiter 过滤器可以用于限流,使用RateLimiter实现来确定是否允许当前请求继续进行,如果请求太大默认会返回HTTP 429-太多请求状态。
- 在pom.xml中添加相关依赖:
<dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-data-redis-reactiveartifactId>
dependency>
- 添加限流策略的配置类,这里有两种策略一种是根据请求参数中的username进行限流,另一种是根据访问IP进行限流
@Configuration
public class RedisRateLimiterConfig {@BeanKeyResolver userKeyResolver() {return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));}@Beanpublic KeyResolver ipKeyResolver() {return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());}
}
- 我们使用Redis来进行限流,所以需要添加Redis和RequestRateLimiter的配置,这里对所有的GET请求都进行了按IP来限流的操作
server:port: 9201
spring:redis:host: localhostpassword: 123456port: 6379cloud:gateway:routes:- id: requestratelimiter_routeuri: http://localhost:8201filters:- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 1 #每秒允许处理的请求数量redis-rate-limiter.burstCapacity: 2 #每秒最大处理的请求数量key-resolver: "#{@ipKeyResolver}" #限流策略,对应策略的Beanpredicates:- Method=GET
logging:level:org.springframework.cloud.gateway: debug
Retry GatewayFilter
对路由请求进行重试的过滤器,可以根据路由请求返回的HTTP状态码来确定是否进行重试。
- 修改配置文件:
spring:cloud:gateway:routes:- id: retry_routeuri: http://localhost:8201predicates:- Method=GETfilters:- name: Retryargs:retries: 1 #需要进行重试的次数statuses: BAD_GATEWAY #返回哪个状态码需要进行重试,返回状态码为5XX进行重试backoff:firstBackoff: 10msmaxBackoff: 50msfactor: 2basedOnPreviousValue: false
- 当调用返回500时会进行重试,访问测试地址:http://localhost:9201/user/111
- 可以发现user-service控制台报错2次,说明进行了一次重试。
2019-10-27 14:08:53.435 ERROR 2280 --- [nio-8201-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root causejava.lang.NullPointerException: nullat com.macro.cloud.controller.UserController.getUser(UserController.java:34) ~[classes/:na]
添加默认过滤器
要添加过滤器并将其应用于所有路由,您可以使用spring.cloud.gateway.default-filters. 此属性采用过滤器列表。以下清单定义了一组默认过滤器:
spring:cloud:gateway:default-filters:- AddResponseHeader=X-Response-Default-Red, Default-Blue- PrefixPath=/httpbin
自定义全局过滤器
当请求与路由匹配时,过滤 Web 处理程序会将 的所有实例GlobalFilter和所有特定于路由的实例添加GatewayFilter到过滤器链中。这个组合的过滤器链是按org.springframework.core.Ordered接口排序的,你可以通过实现getOrder()方法来设置。
由于 Spring Cloud Gateway 区分过滤器逻辑执行的“前”和“后”阶段(请参阅它的工作原理),具有最高优先级的过滤器是“前”阶段的第一个和“后”阶段的最后一个阶段。
参考示例
package cuit.epoch.pymjl.filter;import lombok.extern.log4j.Log4j2;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
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;/*** @author Pymjl* @version 1.0* @date 2022/9/2 17:02**/
@Component
@Log4j2
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("=====================come in MyGlobalFilter==========================");String username = exchange.getRequest().getQueryParams().getFirst("username");if (username == null) {log.error("用户名为null,非法用户");exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);return exchange.getResponse().setComplete();}return chain.filter(exchange);}/*** 得到权重,order越小,优先级越高** @return int*/@Overridepublic int getOrder() {return 0;}
}
我们启动项目进行测试
当带上username参数时访问正常

当不带username参数时网关会路由失败

观察后台输出

跨域过滤器配置
您可以配置网关来控制 CORS 行为
spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowedOrigins: "https://docs.spring.io"allowedMethods:- GET
在前面的示例中,允许来自docs.spring.io所有 GET 请求路径的请求的 CORS 请求。
要为某些网关路由谓词未处理的请求提供相同的 CORS 配置,请将spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping属性设置为true.
通常的配置是:
spring:cloud:gateway:default-filters:# gateway 和下游系统同时支持了跨域,都会向 response header 中增加 Access-Control-Allow-Origin*,所以出现重复的 *。所以需要使用DedupeResponseHeader 来处理一下响应头重复的问题- DedupeResponseHeader=Access-Control-Allow-Origin, RETAIN_UNIQUEglobalcors:cors-configurations:'[/**]':# 允许携带认证信息allow-credentials: true# 允许跨域的源(网站域名/ip),设置*为全部allowedOrigins: "*"# 允许跨域的method, 默认为GET和OPTIONS,设置*为全部allowedMethods: "*"# 允许跨域请求里的head字段,设置*为全部allowedHeaders: "*"
至此,关于Spring Cloud Gateway的进一步解释到这里就结束啦,后面我们会继续介绍Spring Cloud Gateway的动态路由配置以及负载均衡
项目源码:gitee github
参考文章:
Spring Cloud Gateway:新一代API网关服务
- DedupeResponseHeader=Access-Control-Allow-Origin, RETAIN_UNIQUE
globalcors:
cors-configurations:
‘[/**]’:
# 允许携带认证信息
allow-credentials: true
# 允许跨域的源(网站域名/ip),设置为全部
allowedOrigins: ""
# 允许跨域的method, 默认为GET和OPTIONS,设置为全部
allowedMethods: ""
# 允许跨域请求里的head字段,设置为全部
allowedHeaders: ""
至此,关于Spring Cloud Gateway的进一步解释到这里就结束啦,后面我们会继续介绍Spring Cloud Gateway的动态路由配置以及负载均衡项目源码:[gitee](https://gitee.com/pymjl_0/cloud-learn) [github](https://github.com/Pymjl/cloud-learn)参考文章:[Spring Cloud Gateway:新一代API网关服务](https://www.macrozheng.com/cloud/gateway.html#retry-gatewayfilter)[官方文档](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
