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