之前我一直用的是Zuul網關,用過gateway以后感覺比Zuul功能還是強大很多。
Spring Cloud Gateway是基於Spring5.0,Spring Boot2.0和Project Reactor等技術開發的,用來為微服務架構提供一種簡單有效統一的API路由管理方式。
相比Zuul,GateWay不僅僅提供統一的路由方式,還提供了例如:安全,限流,監控/指標,重試機制,熔斷回調,過濾等功能,這些都是可配置的。
原理什么的就不多說了,可以看下官方文檔
首先添加Maven依賴
<!-- gateway --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 熔斷器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <!-- 限流 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis-reactive</artifactId> </dependency> <!-- eureka-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--暴露各種指標--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- zipkin-client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
yml配置詳情如下:
#連接Eureka配置 eureka: client: serviceUrl: defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/ server: port: 8770 spring: main: banner-mode: application: name: dkjk-gateway-service #應用程序名 # redis: # host: localhost # port: 6379 cloud: gateway: routes: - id: my-service-one #我們自定義的路由 ID,保持唯一 #目標服務地址,也可以是http://localhost:8182 PS: 當所用協議為lb時, #gateway將使用 LoadBalancerClient把服務名通過eureka解析為實際的主機和端口,並進行負載均衡。 uri: lb://Eureka中的服務名稱1 # order: 0 #路由規則,Predicate 接受一個輸入參數,返回一個布爾值結果。
#該接口包含多種默認方法來將 Predicate 組合成其他復雜的邏輯(比如:與,或,非)。 predicates: # PS:以下規則可以組合使用 #接收一個匹配路徑的參數來判斷是否走路由。當訪問地址 http://localhost:8770/spring-cloud時
#會自動轉發到地址:http://www.ityouknow.com/spring-cloud - Path=/em/** #可以通過是 POST、GET、PUT、DELETE 等不同的請求方式來進行路由。可以用postman測試,如果符合規則進行路由,否則不進行路由(報404) # - Method=GET #請求時間在 2019年11月04日6點6分6秒之前可以進行路由,在這時間之后停止路由(報404) # - Before=2019-11-04T06:06:06+08:00[Asia/Shanghai] #請求時間在 2019年11月04日16點31分00秒之前不可以進行路由(報404),在這時間之后可以進行路由 # - After=2019-11-05T16:31:00+08:00[Asia/Shanghai] #在這個時間段內可以匹配到此路由,超過這個時間段范圍則不會進行匹配(報404)。可以用在限時搶購的一些場景中。 # - Between=2019-11-04T06:06:06+08:00[Asia/Shanghai], 2019-11-06T06:06:06+08:00[Asia/Shanghai] #兩個參數:1.請求頭中屬性名稱2.正則表達式(也可以是固定值),可以用postman測試,如果符合規則進行路由,否則不進行路由(報404) # - Header=apikey, \d+ #兩個參數:1.Cookie name 值2.正則表達式(也可以是固定值),可以用postman測試,如果符合規則進行路由,否則不進行路由(報404) # - Cookie=apikey, \d+ #只要請求中包含apikey屬性的參數即可匹配路由。如果符合規則進行路由,否則不進行路由(報404) # - Query=apikey # - Host=**.ityouknow.com #通過設置某個 ip 區間號段的請求才會路由,即符合這個網段的可以訪問,例如:http://192.168.1.131:8770/ # - RemoteAddr=192.168.1.1/24 # 過濾規則 filters: #截取路徑的個數 - StripPrefix=1 #在URL路徑前面添加一部分的前綴,例如:配置 - Path=/** , 請求路徑為localhost:8770/idcard,
#會轉變為localhost:8770/identity/idcard # - PrefixPath=/identity - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback #如果服務調用異常會回調自定義的/fallback請求 - id: credit-service uri: lb://Eureka中的服務名稱2 predicates: - Path=/credit/** filters: - StripPrefix=1 - name: Hystrix args: name: fallbackcmd fallbackUri: forward:/fallback #如果服務調用異常會回調自定義的/fallback請求 - name: RequestRateLimiter #名稱必須是 RequestRateLimiter args: redis-rate-limiter.replenishRate: 2 #允許用戶每秒處理多少個請求 redis-rate-limiter.burstCapacity: 3 #令牌桶的容量,允許在一秒鍾內完成的最大請求數 key-resolver: "#{@userKeyResolver}" #使用 SpEL 按名稱引用 bean - name: Retry args: #重試次數,默認值是3次 retries: 3 series: - SERVER_ERROR #滿足的status statuses: - BAD_GATEWAY methods: - GET - POST exceptions: - java.io.IOException - java.util.concurrent.TimeoutException - java.lang.RuntimeException #是否與服務注冊於發現組件進行結合,通過 serviceId 轉發到具體的服務實例。
#默認為 false,設為 true 便開啟通過服務中心的自動根據 serviceId 創建路由的功能。 #這個不用配置也可以 # discovery: # locator: # enabled: true # hystrix 信號量隔離,30秒后自動超時 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 30000 logging: level: org.springframework.cloud.gateway: debug
以上配置啟動類中用到的注解
package com.dkjk.gateway; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker public class DkjkGatewayServiceApplication { public static void main(String[] args) { SpringApplication.run(DkjkGatewayServiceApplication.class, args); } }
限流配置代碼
package com.dkjk.gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; /** * @Description: * @Author: qjc * @Date: 2019/11/6 */ @Configuration public class Config { @Bean KeyResolver userKeyResolver() { // return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));//根據請求參數中的 user 字段來限流 return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());//根據請求 IP 地址來限流 } }
熔斷回調代碼:
package com.dkjk.gateway.controller; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @Description: * @Author: qjc * @Date: 2019/11/6 */ @RestController @Slf4j public class FallbackController { @GetMapping("/fallback") public String fallback() { log.info("回調了"); return "Hello World!\nfrom gateway"; } }