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