SpringCloud网关Gateway入门介绍
注意
- Spring Cloud Gateway构建在SpringBoot 2.0、Spring WebFlux和Project Reactor上。因此,许多熟悉的同步库(例如Spring Data and Spring Security)和模式在使用Spring Cloud网关时可能不适用
- SpringCloudGateway需要SpringBoot和SpringWebFlux提供的netty运行时。它不能在传统的servlet容器中工作,也不能作为war而构建。
- 截止今天为止(即Greenwich.SR1版本),gateway和web不能共存,也就是org.springframework.boot:spring-boot-starter-web这个库要移除掉
综述
-
gateway主要有三个概念:Route(路由),Predicate(谓词),Filter(过滤器)
-
以上过滤链的过程可以用以下例子说明(注意日志的打印顺序):
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import reactor.core.publisher.Mono; /** * 全局过滤器演示,order越低优先级越高 * 最终输出日志为 * first pre filter * second pre filter * third pre filter * first post filter * second post filter * third post filter */ @Configuration public class ExampleConfiguration { private Logger log = LoggerFactory.getLogger(ExampleConfiguration.class); @Bean @Order(-1) public GlobalFilter a() { return (exchange, chain) -> { log.info("first pre filter"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { log.info("third post filter"); })); }; } @Bean @Order(0) public GlobalFilter b() { return (exchange, chain) -> { log.info("second pre filter"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { log.info("second post filter"); })); }; } @Bean @Order(1) public GlobalFilter c() { return (exchange, chain) -> { log.info("third pre filter"); return chain.filter(exchange).then(Mono.fromRunnable(() -> { log.info("first post filter"); })); }; } }
-
其中predicates主要有以下几种:
After 可以指定在某个时间之后的请求
Before 可以指定在某个时间之前的请求
Between 可以指定在某个时间段之内的请求
Cookie 可以指定cookie
Header 可以指定请求头
Host 可以指定请求的host
Method 可以指定请求的方式
Path 可以指定某个路径
Query 可以指定带有某个参数
RemoteAddr 可以指定某个远程访问地址 -
其中filters主要有以下几种:
AddRequestHeader
AddRequestParameter
AddResponseHeader
DedupeResponseHeader
PrefixPath
server:
port: 4120
# servlet:
# context-path:
spring:
cloud:
gateway:
enabled: true # if you do not want the gateway to be enabled ,set false
routes:
- id: id-a
uri: https://www.baidu.com #支持lb 如lb://service
predicates:
- Path= /a/**
filters:
- StripPrefix= 1 #看名字就知道,这是为了跳过前缀,否则就会前缀也加在路径上,看个人需求
- id: id-b
uri: https://hao.360.com
predicates:
- Path= /b/**
filters:
- StripPrefix= 1
- 如果context-path不为空,那依然不影响,仍然可以通过 http://localhost:4120/a 访问到 https://www.baidu.com ,这里的context-path不会起作用
- 上面的StripPrefix这个意思就是跳过前缀,值的意思是跳过几个,举个栗子:假如用户访问 http://localhost:4120/a/b/c ,那么实际访问的是:
- https://www.baidu.com/b/c (StripPrefix=1)
- https://www.baidu.com/a/b/c (StripPrefix=0)
- https://www.baidu.com/c (StripPrefix=2)
- 这下明白了吧
- 当然如果想在代码里配置,这也是支持的,上面的配置等价于下面的代码
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;
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("id-a", r -> r.path("/a/**").filters(f -> f.stripPrefix(1)).uri("https://www.baidu.com"))
.route("id-b", r -> r.path("/b/c/**").filters(f -> f.stripPrefix(2)).uri("https://hao.360.com"))
.build();
}
}
限流
-
官方说明: https://cloud.spring.io/spring-cloud-gateway/spring-cloud-gateway.html#_requestratelimiter_gatewayfilter_factory
-
很多时候我们需要对接口进行限流,或者对恶意访问进行防范,这时就需要限制同一ip或同一接口的访问次数
-
由于限流的实现依赖于redis,因此要引入
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
-
当然还得有个redis服务(至于redis服务怎么弄我就不讲了),有了redis服务,在yml中配置一下
spring: redis: host: 192.168.25.105 port: 6379
-
通过以上操作基本环境就搭建好了,下面配置一下要限流的路由
server: port: 4120 spring: cloud: gateway: enabled: true # if you do not want the gateway to be enabled ,set false routes: - id: id-c uri: http://www.baidu.com predicates: - Path= /d/** filters: - StripPrefix= 1 - name: RequestRateLimiter #名称是固定的,不能修改 args: redis-rate-limiter.replenishRate: 1 #允许用户每秒处理多少个请求 redis-rate-limiter.burstCapacity: 5 #令牌桶的容量,允许在一秒钟内完成的最大请求数 key-resolver: "#{@userKeyResolver}" #跟提供bean类的方法名一致,指定具体要限流的是接口还是ip等 redis: host: 192.168.25.105 port: 6379
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; 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; import reactor.core.publisher.Mono; @Configuration public class GateWayConfig { @Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getPath().value());//接口限流 // return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); //ip限流 //return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); //用户限流,必须带有user参数才有效 } }
-
如上配置就实现了对接口的限流,访问接口 http://localhost:4120/d ,可以在redis服务中看到
-
表明限流已经在起作用了
代码示例
- github-demo: https://github.com/huweijian5/oauth2-demo/tree/master/gateway
参考
Spring Cloud Gateway
https://cloud.spring.io/spring-cloud-gateway/spring-cloud-gateway.html
Spring Cloud Gateway 2.1.0 中文官网文档 - 云+社区 - 腾讯云
https://cloud.tencent.com/developer/article/1403887
SpringCloud Gateway的基本入门和注意点 - zzzgd_666的博客 - CSDN博客
https://blog.csdn.net/zzzgd_666/article/details/86095716
Spring Cloud Gateway 限流操作 - u010889990的专栏 - CSDN博客
https://blog.csdn.net/u010889990/article/details/81169328