javascript
SpringCloud11-GateWay网关
1、概述
zuul 1.x:https://github.com/Netflix/zuul/wiki
Spring Cloud GateWay官網:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
1.1 GateWay是什么?
Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0、Spring Boot 2.0 和 Project Reactor 等技術開發的網關,Spring Cloud Gateway 旨在為微服務架構提供一種簡單有效的、統一的 API 路由管理方式。
Spring Cloud Gateway 作為 Spring Cloud 生態系中的網關,其目標是替代 Netflix Zuul,它不僅提供統一的路由方式,并且基于 Filter 鏈的方式提供了網關基本的功能,例如:安全、監控/埋點和限流等。
Spring Cloud Gateway 依賴 Spring Boot 和 Spring WebFlux,基于 Netty 運行。它不能在傳統的 servlet 容器中工作,也不能構建成 war 包。
一句話總結:Gateway使用的是Webflux中的reactor-netty響應式編程組件,底層使用了Netty通訊框架。
1.2 GateWay的作用
- 反向代理
- 鑒權
- 瀏覽控制
- 熔斷
- 日志監控
1.3 網關GateWay在微服務中的位置
1.4 Gateway的三大核心概念
-
Route(路由)
Route 是最核心的路由元素,它定義了ID,目標URI ,predicates的集合與filter的集合,如果Predicate聚合返回真,則匹配該路由
-
Predicate(斷言)
基于java8的函數接口Predicate,其輸入參數類型ServerWebExchange,其作用就是允許開發人員根據當前的http請求進行規則的匹配,比如說http請求頭,請求時間等,匹配的結果將決定執行哪種路由
-
Filter(過濾)
指的是Spring框架中GatewayFilter的實例,使用過濾器,可以在請求被路由前或者之后對請求進行修改;
web請求通過一系列的匹配條件,定位到真正的服務節點,并在這個轉發過程的前后,進行一些精細化的控制,predicate就是我們的匹配條件,而filter則是一個無所不能的攔截器,有了這兩個之后,再加上目標uri,就可以實現一個具體的路由了。
1.5 GateWay的工作流程
官網的工作流程圖:
Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. All “pre” filter logic is executed. Then the proxy request is made. After the proxy request is made, the “post” filter logic is run.客戶端向springcloudgateway發出請求。
如果在Gateway Handler Mapping(網關處理程序映射)中找到與請求相匹配的路由,則將其發送到Gateway Web Handler(網關Web處理程序)。
Handler再通過指定的過濾器鏈來將請求發送到我們實際的服務中執行業務邏輯,然后返回。過濾器被虛線分開的原因是過濾器可以在發送代理請求之前(pre)和之后(post)執行業務邏輯。
Filter在“Pre”類型的過濾器中可以做參數校驗,權限校驗,流量監控,日志輸出和協議轉換等操作;在“Post”類型的過濾器中可以做響應內容,響應頭的修改,日志的輸出,流量監控等操作。Filer的功能強大。
2、入門案例
2.1 創建模塊cloud-gateway-gateway9527
2.1.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud2020</artifactId><groupId>com.zdw.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-gateway-gateway9527</artifactId><dependencies><!--gateway網關--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--gateway無需web和actuator,如果有的話啟動會報錯--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--熱部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--引入自定義的公共包,回用到里面的實體--><dependency><groupId>com.zdw.springcloud</groupId><artifactId>cloud-api-common</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies></project>2.1.2 application.yml配置
server:port: 9527spring:application:name: cloud-gatewaycloud:gateway:discovery:locator:enabled: true # 開啟從注冊中心動態創建路由的功能,利用微服務名稱進行路由routes:- id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名#匹配后提供服務的路由地址uri: http://localhost:8001predicates:- Path=/payment/get/** # 斷言,路徑相匹配的進行路由- id: payment_route2uri: http://localhost:8001predicates:- Path=/payment/lb/** #斷言,路徑相匹配的進行路由eureka:instance:hostname: cloud-gateway-serviceclient:fetch-registry: trueregister-with-eureka: trueservice-url:# 單擊版defaultZone: http://localhost:7001/eureka# 集群版# defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka我們現在是要在服務 cloud-provider-payment8001 外面包上一層9527的網關,所以我們配置的路由是針對cloud-provider-payment8001服務的,等會測試的時候,需要把cloud-provider-payment8001啟動。
2.1.3 主啟動類
package com.zdw.springcloud;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;/*** @author ZDW* @create 2020-08-19 16:00*/ @SpringBootApplication //作為eureka的客戶端注冊進eureka中 @EnableEurekaClient public class GatewayMain9527 {public static void main(String[] args) {SpringApplication.run(GatewayMain9527.class,args);} }2.1.4 測試
1、啟動cloud-eureka-server7001服務
2、啟動cloud-provider-payment8001服務
3、啟動cloud-gateway-gateway9527服務
瀏覽器訪問:
添加網關前,直接訪問8001:http://localhost:8001/payment/get/1 是可以訪問到數據的
添加網關后,直接訪問9527:http://localhost:9527/payment/get/1 也是可以訪問成功的
通過配置路由和斷言,在8001的外面包了一層9527的網關,對外暴露的是9527的地址。
2.2 通過Java代碼配置路由
在上面的application.yml文件中,我們是配置了路由的,不過除了這種方式外,還支持通過Java配置類的方式來進行路由配置:
業務需求:通過9527網關訪問到外網的百度新聞網址
2.2.1 配置類:GatewayConfig
package com.zdw.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 ZDW* @create 2020-08-19 16:18* 通過Java配置類來進行路由的配置*/ @Configuration public class GatewayConfig {/*** 配置了一個id為route-name的路由規則* 當訪問地址 http://localhost:9527/guonei時會自動轉發到地址: http://news.baidu.com/guonei* @param builder* @return*/@Beanpublic RouteLocator customRouteLocator(RouteLocatorBuilder builder) {RouteLocatorBuilder.Builder routes = builder.routes();routes.route("path_route_zdw1",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_zdw1",r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build();return routes.build();} }2.2.2 測試
重啟服務:cloud-gateway-gateway9527,然后瀏覽器訪問:http://localhost:9527/guonei 會被路由到百度:http://news.baidu.com/guonei
3、通過服務名實現動態路由
在上面的application.yml中,我們配置的路由的uri是:uri: http://localhost:8001,如果服務是多個,比如有8001和8002,此時我們這里寫的8001,那么就只會把請求轉發到8001,這樣明顯不太好,無法實現負載均衡。所以接下來,要通過配置,動態的實現路由,可以把請求轉發到8001和8002兩個服務。
默認情況下Gatway會根據注冊中心注冊的服務列表, 以注冊中心上微服務名為路徑創建動態路由進行轉發,從而實現動態路由的功能;
3.1 修改application.yml
server:port: 9527spring:application:name: cloud-gatewaycloud:gateway:discovery:locator:enabled: true # 開啟從注冊中心動態創建路由的功能,利用微服務名稱進行路由routes:- id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名#匹配后提供服務的路由地址#uri: http://localhost:8001# lb是固定的,表示的是協議lb,表示啟用Gateway的負載均衡功能,# cloud-payment-service是cloud-provider-payment8001和cloud-provider-payment8002注冊到eureka注冊中的服務名稱uri: lb://cloud-payment-servicepredicates:- Path=/payment/get/** # 斷言,路徑相匹配的進行路由- id: payment_route2#uri: http://localhost:8001uri: lb://cloud-payment-servicepredicates:- Path=/payment/lb/** #斷言,路徑相匹配的進行路由eureka:instance:hostname: cloud-gateway-serviceclient:fetch-registry: trueregister-with-eureka: trueservice-url:# 單擊版defaultZone: http://localhost:7001/eureka# 集群版# defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka3.2 測試
1、啟動cloud-eureka-server7001服務
2、啟動cloud-provider-payment8001服務和cloud-provider-payment8002服務(這兩個服務配置的是eureka的單機版)
3、啟動cloud-gateway-gateway9527服務
瀏覽器訪問:http://localhost:9527/payment/lb 可以看到8001和8002交替進行
4、Predicate
Predicate 是基于java8的函數接口Predicate,其輸入參數類型ServerWebExchange,其作用就是允許開發人員根據當前的http請求進行規則的匹配,比如說http請求頭,請求時間等,匹配的結果將決定執行哪種路由;
在啟動9527服務的日志中,可以看到:
可以看到這些都是路由謂詞工廠 (Route Predicate Factories)的相關謂詞。
4.1 Route Predicate Factories是什么
Spring Cloud Gateway的路由謂詞工廠 (Route Predicate Factories),路由謂詞工廠的作用是:符合Predicate的條件,就使用該路由的配置,否則就不管。
Spring Cloud Gateway將路由匹配作為Spring WebFlux HandlerMapping基礎架構的一部分。
Spring Cloud Gateway包括許多內置的Route PredicateI。所有這些Predicate都與HTTP請求的不同屬性匹配。多個RoutePredicate.工廠可以進行組合。
Spring Cloud Gateway創建Route對象時,使用RoutePredicateFactory創建Predicate對象, Predicate對象可以賦值給Route。 Spring Cloud Gateway包含許多內置的Route Predicate Factories。
所有這些謂詞都匹配HTTP請求的不同屬性,多種謂詞工廠可以互相組合,并通過邏輯and。
4.2 常用的Route Predicate Factories
參考:https://www.cnblogs.com/bjlhx/p/9785926.html
4.2.1 After Route Predicate
spring:cloud:gateway:routes:- id: after_routeuri: https://example.orgpredicates:# 這個是美國時區,表示要在這個時間只后,上面的路由才會生效- After=2017-01-20T17:42:47.789-07:00[America/Denver]上面- After配置的時間是美國時間,可以使用下面的代碼得到當前時區的時間:
System.out.println(ZonedDateTime.now()); //2020-08-19T17:01:44.755+08:00[Asia/Shanghai]其他的省略
5、Filter
可以參考:https://blog.csdn.net/forezp/article/details/85057268
路由過濾器可用于修改進入的HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用。Spring Cloud Gateway內置了多種路由過濾器,他們都由GatewayFilter的工廠 類來產生。
5.1 常用的Filter
5.1.1 單個路由的gateway filter
它在配置文件中的寫法同predict類似;
過濾器允許以某種方式修改傳入的HTTP請求或傳出的HTTP響應。過濾器可以限定作用在某些特定請求路徑上。 Spring Cloud Gateway包含許多內置的GatewayFilter工廠。
GatewayFilter工廠同上一篇介紹的Predicate工廠類似,都是在配置文件application.yml中配置,遵循了約定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名稱,而不需要寫全部的類名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中寫AddRequestHeader,而不是全部類名。在配置文件中配置的GatewayFilter Factory最終都會相應的過濾器工廠類處理。
官網:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories
5.1.2 針對于所有路由的global gateway filer
GlobalFilter : 全局過濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過GatewayFilterAdapter包裝成GatewayFilterChain可識別的過濾器,它為請求業務以及路由的URI轉換為真實業務服務的請求地址的核心過濾器,不需要配置,系統初始化時加載,并作用在每個路由上。
官網:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#global-filters
5.2 自定義全局GlobalFilter
自定義的Filter需要實現GlobalFilter和Ordered接口;
作用:全局日志記錄和統一網關鑒權等一系列操作;
5.2.1 需求
判斷請求中是否有參數username,如果沒有,就提示非法用戶
5.2.2 自定義MyLogGatewayFilter
package com.zdw.springcloud.filter;import lombok.extern.slf4j.Slf4j; 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;import java.util.Date;/*** @author ZDW* @create 2020-08-19 17:38*/ @Component @Slf4j public class MyLogGatewayFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("****** come in MyLogGateWayFilter: " + new Date());String uname = exchange.getRequest().getQueryParams().getFirst("uname");if(uname == null) {log.info("*****用戶名為null,非法用戶,o(╥﹏╥)o");exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);return exchange.getResponse().setComplete();}return chain.filter(exchange);}/*** 加載過濾器的順序,數字越小,優先級越高*/@Overridepublic int getOrder() {return 0;} }5.2.3 測試
1、啟動cloud-eureka-server7001服務
2、啟動cloud-provider-payment8001服務和cloud-provider-payment8002服務(這兩個服務配置的是eureka的單機版)
3、啟動cloud-gateway-gateway9527服務
瀏覽器訪問:http://localhost:9527/payment/lb ,沒有任何響應,可以看到后臺打印了:*****用戶名為null,非法用戶,o(╥﹏╥)o ,這說明已經被我們的過濾器把請求攔截了
瀏覽器訪問:http://localhost:9527/payment/lb?uname=z3 可以得到正常的響應,端口8001和8002交替顯示
}
/*** 加載過濾器的順序,數字越小,優先級越高*/ @Override public int getOrder() {return 0; }}
### 5.2.3 測試1、啟動cloud-eureka-server7001服務2、啟動cloud-provider-payment8001服務和cloud-provider-payment8002服務(這兩個服務配置的是eureka的單機版)3、啟動cloud-gateway-gateway9527服務瀏覽器訪問:http://localhost:9527/payment/lb ,沒有任何響應,可以看到后臺打印了:*****用戶名為null,非法用戶,o(╥﹏╥)o ,這說明已經被我們的過濾器把請求攔截了瀏覽器訪問:http://localhost:9527/payment/lb?uname=z3 可以得到正常的響應,端口8001和8002交替顯示總結
以上是生活随笔為你收集整理的SpringCloud11-GateWay网关的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript判断当前浏览器是否为
- 下一篇: 树莓派python蓝牙_树莓派的蓝牙操作