SpringCloud Gateway的路由,過濾器和限流解讀
Spring 官方最終還是按捺不住推出了自己的網(wǎng)關(guān)組件:Spring Cloud Gateway ,相比之前我們使用的 Zuul(1.x) 它有哪些優(yōu)勢呢?
Zuul(1.x) 基于 Servlet,使用阻塞 API,它不支持任何長連接,如 WebSockets,Spring Cloud Gateway 使用非阻塞 API,支持 WebSockets,支持限流等新特性。
Spring Cloud Gateway
Spring Cloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡單有效的統(tǒng)一的 API 路由管理方式。
注意:
Spring Cloud Gateway是基于Spring Boot 2.x, Spring WebFlux和Project Reactor 構(gòu)建的。
因此,在使用Spring Cloud Gateway時,許多不熟悉的同步庫(例如,Spring Data和Spring Security)和模式可能不適用。
如果您對這些項目不熟悉,建議您在使用Spring Cloud Gateway之前先閱讀它們的文檔,以熟悉一些新概念。
Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty運(yùn)行時。它不能在傳統(tǒng)的Servlet容器中或作為WAR構(gòu)建。
Spring Cloud Gateway 作為 Spring Cloud 生態(tài)系統(tǒng)中的網(wǎng)關(guān),目標(biāo)是替代 Netflix Zuul,其不僅提供統(tǒng)一的路由方式,并且基于 Filter 鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全,監(jiān)控/指標(biāo),和限流。
Spring Cloud Gateway 的特征:
- 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
- 動態(tài)路由
- Predicates 和 Filters 作用于特定路由
- 集成 Hystrix 斷路器
- 集成 Spring Cloud DiscoveryClient
- 易于編寫的 Predicates 和 Filters
- 限流
- 路徑重寫
相關(guān)概念:
- Route(路由):這是網(wǎng)關(guān)的基本構(gòu)建塊。它由一個 ID,一個目標(biāo) URI,一組斷言和一組過濾器定義。如果斷言為真,則路由匹配。
- Predicate(斷言):這是一個 Java 8 的 Predicate。輸入類型是一個 ServerWebExchange。我們可以使用它來匹配來自 HTTP 請求的任何內(nèi)容,例如 headers 或參數(shù)。
- Filter(過濾器):這是org.springframework.cloud.gateway.filter.GatewayFilter的實例,我們可以使用它修改請求和響應(yīng)。
Spring Cloud Gateway 網(wǎng)關(guān)路由有兩種配置方式:
- 在配置文件 yml 中配置通過@Bean自定義 RouteLocator,在啟動主類 Application 中配置
- 這兩種方式是等價的,建議使用 yml 方式進(jìn)配置。
pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies>
application.yml
server: port: 8080 spring: cloud: gateway: routes: - id: bamboo_route uri: https://blog.csdn.net/ predicates: - Path=/blogdevteam
yml方式配置路由
id
:我們自定義的路由 ID,保持唯一uri
:目標(biāo)服務(wù)地址predicates
:路由條件,Predicate 接受一個輸入?yún)?shù),返回一個布爾值結(jié)果。該接口包含多種默認(rèn)方法來將 Predicate 組合成其他復(fù)雜的邏輯(比如:與,或,非)。filters
:過濾規(guī)則,本示例暫時沒用。
啟動類:代碼方式配置路由
package com.bamboo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; /** * @program: spring-gateway * @description: Application * @author: Bamboo zjcjava@163.com * @create: 2019-10-26 20:00 **/ @SpringBootApplication public class Application { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() // basic proxy .route(r -> r.path("/zjcjava") .uri("https://blog.csdn.net//")) .build(); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
http://localhost:8080/zjcjava
對應(yīng)訪問的地址是
https://blog.csdn.net/zjcjavahttp://localhost:8080/blogdevteam
對應(yīng)訪問的地址是
https://blog.csdn.net/blogdevteam
可以看出來,它會自動在url路徑/后面加上對應(yīng)的路由地址
predicates路由斷言工廠
Spring Cloud Gateway將路由作為Spring WebFlux HandlerMapping基礎(chǔ)架構(gòu)的一部分進(jìn)行匹配。Spring Cloud Gateway包括許多內(nèi)置的Route Predicate工廠。所有這些謂詞都與HTTP請求的不同屬性匹配。多個Route Predicate工廠可以合并,也可以通過邏輯合并and。
Predicate 來源于 Java 8,是 Java 8 中引入的一個函數(shù),Predicate 接受一個輸入?yún)?shù),返回一個布爾值結(jié)果。該接口包含多種默認(rèn)方法來將 Predicate 組合成其他復(fù)雜的邏輯(比如:與,或,非)。可以用于接口請求參數(shù)校驗、判斷新老數(shù)據(jù)是否有變化需要進(jìn)行更新操作。
在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性實現(xiàn)了各種路由匹配規(guī)則,有通過 Header、請求參數(shù)等不同的條件來進(jìn)行作為條件匹配到對應(yīng)的路由。網(wǎng)上有一張圖總結(jié)了 Spring Cloud 內(nèi)置的幾種 Predicate 的實現(xiàn)。
spring: cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true ##會使用serviceId轉(zhuǎn)發(fā)到具體的服務(wù)IP上的服務(wù) routes: - id: after_route uri: https://example.org predicates: - After=2017-01-20T17:42:47.789-07:00[America/Denver] - Before=2017-01-20T17:42:47.789-07:00[America/Denver] - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] - Cookie=chocolate, ch.p - Header=X-Request-Id, \d+ - Host=**.somehost.org,**.anotherhost.org - Method=GET - Path=/foo/{segment},/bar/{segment} - Query=baz - RemoteAddr=192.168.1.1/24 - id: weight_high uri: https://weighthigh.org predicates: - Weight=group1, 8 - id: weight_low uri: https://weightlow.org predicates: - Weight=group1, 2
spring.cloud.gateway.discovery.locator.enabled:使用eurake注冊服務(wù)后:是否與服務(wù)發(fā)現(xiàn)組件ID進(jìn)行結(jié)合,通過routes中的serviceId 轉(zhuǎn)發(fā)到具體的服務(wù)實例。
默認(rèn)為false,設(shè)為true便開啟通過服務(wù)中心的自動根據(jù) serviceId 創(chuàng)建路由的功能。
- 后路線斷言工廠:After=2017年1月20日17:42山區(qū)時間(丹佛)之后的所有請求匹配
- 路線斷言工廠之前:Before=2017年1月20日17:42山區(qū)時間(丹佛)之前的所有請求匹配。
- 路線斷言工廠之間- Between=2017年1月20日山區(qū)時間(丹佛)之后和2017年1月21日17:42山區(qū)時間(丹佛)之后的所有請求匹配
- Cookie路線斷言工廠 Cookie=請求匹配一個名為chocolatewho的值為ch.p正則表達(dá)式匹配的cookie
- 標(biāo)頭路由斷言工廠 - Header=匹配請求具有名為X-Request-Id其值為\d+正則表達(dá)式匹配(具有一個或多個數(shù)字的值)的標(biāo)頭
- 主機(jī)路由斷言工廠 - Host=請求的Host標(biāo)頭中包含值www.somehost.org或beta.somehost.org,則此路由將匹配www.anotherhost.org
- 方法路線斷言工廠 - Method=此路由將匹配GET方式的請求
- 路徑路線斷言工廠 - Path=將匹配:/foo/1或/foo/bar或/bar/baz
- 查詢路由斷言工廠 - Query=匹配請求包含baz查詢參數(shù)
- RemoteAddr路由斷言工廠 - RemoteAddr=請求的遠(yuǎn)程地址為192.168.1.1/24之間的IP,則此路由將匹配192.168.1.10
- 權(quán)重路線斷言工廠 將約80%的流量轉(zhuǎn)發(fā)至weighthigh.org,并將約20%的流量轉(zhuǎn)發(fā)至weightlow.org
全局過濾器
該GlobalFilter接口具有與相同的簽名GatewayFilter。這些是特殊過濾器,有條件地應(yīng)用于所有路由。(此界面和用法可能會在將來的里程碑中更改)。
全局過濾器和GatewayFilter的組合訂購
當(dāng)請求進(jìn)入(并與路由匹配)時,過濾Web處理程序會將的所有實例GlobalFilter和所有特定GatewayFilter于路由的實例添加到過濾器鏈中。該組合的過濾器鏈按org.springframework.core.Ordered接口排序,可以通過實現(xiàn)該getOrder()方法進(jìn)行設(shè)置。
由于Spring Cloud Gateway區(qū)分了執(zhí)行過濾器邏輯的“前”階段和“后”階段(請參閱:工作原理),因此優(yōu)先級最高的過濾器將在“前”階段中處于第一個階段,而在“后”階段中處于最后一個階段“-相。
ExampleConfiguration.java
//放入application啟動類中main方法后面即可 @Bean public CustomGlobalFilter tokenFilter() { return new CustomGlobalFilter(); } /** * @program: spring-gateway * @description: 全局過濾器 * @author: Bamboo zjcjava@163.com * @create: 2019-10-26 23:06 **/ public class CustomGlobalFilter implements GlobalFilter, Ordered { private static final Logger log = LoggerFactory.getLogger(CustomGlobalFilter.class); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("custom global filter....................................."); // 添加全局鑒權(quán) String token = exchange.getRequest().getQueryParams().getFirst("token"); if (token == null || token.isEmpty()) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return -1; } }
這里我創(chuàng)建了一個全局的鑒權(quán)過濾器,只有參數(shù)中帶有token值才能繼續(xù),否則提示無權(quán)訪問
http://localhost:8080/zjcjava?token=aa
fGatewayFilter工廠
路由過濾器允許以某種方式修改傳入的HTTP請求或傳出的HTTP響應(yīng)。路由過濾器適用于特定路由。Spring Cloud Gateway包括許多內(nèi)置的GatewayFilter工廠。
filters配置
修改配置文件如下:抓喲是 path,filters
server: port: 8080 spring: application: name: spring-cloud-gateway cloud: gateway: routes: - id: bamboo_route uri: https://blog.csdn.net/ predicates: # - Path=/blogdevteam - Path=/test/blogdevteam filters: - StripPrefix=1 #去掉前綴 - AddResponseHeader=X-Response-Default-Foo, Default-Bar #返回消息頭添加head信息
StripPrefix=1 #去掉第1個前綴以/分割
AddResponseHeader返回報文消息頭添加head信息
這里只列舉幾個重要的過濾器
Hystrix GatewayFilter工廠
Hystrix是Netflix的一個庫,用于實現(xiàn)斷路器模式。Hystrix GatewayFilter允許您將斷路器引入網(wǎng)關(guān)路由,保護(hù)您的服務(wù)免受級聯(lián)故障的影響,并允許您在下游故障的情況下提供后備響應(yīng)。
要在項目中啟用Hystrix GatewayFilters,請spring-cloud-starter-netflix-hystrix從Spring Cloud Netflix添加依賴項。
Hystrix GatewayFilter工廠需要一個name參數(shù),它是的名稱HystrixCommand。
spring: cloud: gateway: routes: - id: hystrix_route uri: https://example.org filters: - Hystrix=myCommandName
這會將其余的過濾器包裝在HystrixCommand帶有命令名的中myCommandName。
Hystrix過濾器還可以接受可選fallbackUri參數(shù)。當(dāng)前,僅forward:支持計劃的URI。如果調(diào)用了后備,則請求將被轉(zhuǎn)發(fā)到與URI相匹配的控制器。
限流RequestRateLimiter GatewayFilter工廠
RequestRateLimiter GatewayFilter Factory使用一種RateLimiter實現(xiàn)來確定是否允許繼續(xù)當(dāng)前請求。如果不是,HTTP 429 - Too Many Requests則返回狀態(tài)(默認(rèn))。
此過濾器采用一個可選keyResolver參數(shù)和特定于速率限制器的參數(shù)(請參見下文)。
keyResolver是實現(xiàn)KeyResolver接口的bean 。在配置中,使用SpEL按名稱引用bean。#{@myKeyResolver}是SpEL表達(dá)式,它引用名稱為的bean myKeyResolver。
Redis RateLimiter
redis實現(xiàn)基于Stripe所做的工作。它需要使用spring-boot-starter-data-redis-reactiveSpring Boot啟動器。
使用的算法是令牌桶算法。
該redis-rate-limiter.replenishRate是多么的每秒許多請求你希望用戶被允許做,沒有任何下降的請求。這是令牌桶被填充的速率。
redis-rate-limiter.burstCapacity是允許用戶在一個單一的第二做請求的最大數(shù)目。這是令牌桶可以容納的令牌數(shù)。將此值設(shè)置為零將阻止所有請求。
通過在replenishRate和中設(shè)置相同的值,可以達(dá)到穩(wěn)定的速率burstCapacity。設(shè)置burstCapacity大于可以允許臨時爆發(fā)replenishRate。在這種情況下,速率限制器需要在突發(fā)之間間隔一段時間(根據(jù)replenishRate),因為2個連續(xù)的突發(fā)將導(dǎo)致請求丟失(HTTP 429 - Too Many Requests)。
application.yml
spring: cloud: gateway: routes: - id: requestratelimiter_route uri: https://example.org filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20
配置文件
@Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user")); }
這定義了每個用戶10的請求速率限制。允許20個并發(fā),但是下一秒只有10個請求可用。這KeyResolver是一個簡單的獲取user請求參數(shù)的參數(shù)(注意:不建議在生產(chǎn)中使用)。
速率限制器也可以定義為實現(xiàn)RateLimiter接口的Bean 。在配置中,使用SpEL按名稱引用bean。#{@myRateLimiter}是SpEL表達(dá)式,它引用名稱為的bean myRateLimiter。
application.yml
spring: cloud: gateway: routes: - id: requestratelimiter_route uri: https://example.org filters: - name: RequestRateLimiter args: rate-limiter: "#{@myRateLimiter}" key-resolver: "#{@userKeyResolver}"
參考文檔
官方參考文檔:
https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.0.RC1/reference/html/
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java項目導(dǎo)入IDEA的流程配置以及常見問題解決方法
通常一個團(tuán)隊中可能有人用eclipse,有人用intelliJ,那么經(jīng)常會出現(xiàn)需要導(dǎo)入別人用eclipse建好的web項目,下面這篇文章主要給大家介紹了關(guān)于Java項目導(dǎo)入IDEA的流程配置以及常見問題解決方法的相關(guān)資料,需要的朋友可以參考下2023-05-05spring?boot整合mongo查詢converter異常排查記錄
這篇文章主要為大家介紹了spring?boot整合mongo查詢時拋出converter異常的排查解決記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03linux下用renameTo方法修改java web項目中文件夾名稱的實例
下面小編就為大家?guī)硪黄猯inux下用renameTo方法修改java web項目中文件夾名稱的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06SpringBoot整合SpringSecurity和JWT和Redis實現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證
Spring Security是一個可以為Java應(yīng)用程序提供全面安全服務(wù)的框架,同時它也可以輕松擴(kuò)展以滿足自定義需求,本文主要介紹了SpringBoot整合SpringSecurity和JWT和Redis實現(xiàn)統(tǒng)一鑒權(quán)認(rèn)證,感興趣的可以了解一下2023-11-11Spring原生Rpc六種的正確打開方式實現(xiàn)示例
這篇文章主要為大家展示了Spring原生Rpc六種的正確打開方式實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步早日升職加薪2022-02-02