SpringBoot實戰電商項目mall(20k+star)地址:github.com/macrozheng/…java
Spring Cloud Gateway 爲 SpringBoot 應用提供了API網關支持,具備強大的智能路由與過濾器功能,本文將對其用法進行詳細介紹。react
Gateway是在Spring生態系統之上構建的API網關服務,基於Spring 5,Spring Boot 2和 Project Reactor等技術。Gateway旨在提供一種簡單而有效的方式來對API進行路由,以及提供一些強大的過濾器功能, 例如:熔斷、限流、重試等。git
Spring Cloud Gateway 具備以下特性:github
這裏咱們建立一個api-gateway模塊來演示Gateway的經常使用功能。redis
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
複製代碼
Gateway 提供了兩種不一樣的方式用於配置路由,一種是經過yml文件來配置,另外一種是經過Java Bean來配置,下面咱們分別介紹下。spring
server:
port: 9201
service-url:
user-service: http://localhost:8201
spring:
cloud:
gateway:
routes:
- id: path_route #路由的ID
uri: ${service-url.user-service}/user/{id} #匹配後路由地址
predicates: # 斷言,路徑相匹配的進行路由
- Path=/user/{id}
複製代碼
啓動eureka-server,user-service和api-gateway服務,並調用該地址測試:http://localhost:9201/user/1api
咱們發現該請求被路由到了user-service的該路徑上:http://localhost:8201/user/1bash
/** * Created by macro on 2019/9/24. */
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route2", r -> r.path("/user/getByUsername")
.uri("http://localhost:8201/user/getByUsername"))
.build();
}
}
複製代碼
從新啓動api-gateway服務,並調用該地址測試:http://localhost:9201/user/getByUsername?username=macrocookie
咱們發現該請求被路由到了user-service的該路徑上:http://localhost:8201/user/getByUsername?username=macro架構
Spring Cloud Gateway將路由匹配做爲Spring WebFlux HandlerMapping基礎架構的一部分。 Spring Cloud Gateway包括許多內置的Route Predicate工廠。 全部這些Predicate都與HTTP請求的不一樣屬性匹配。 多個Route Predicate工廠能夠進行組合,下面咱們來介紹下一些經常使用的Route Predicate。
注意:Predicate中提到的配置都在application-predicate.yml文件中進行修改,並用該配置啓動api-gateway服務。
在指定時間以後的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: after_route
uri: ${service-url.user-service}
predicates:
- After=2019-09-24T16:30:00+08:00[Asia/Shanghai]
複製代碼
在指定時間以前的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: before_route
uri: ${service-url.user-service}
predicates:
- Before=2019-09-24T16:30:00+08:00[Asia/Shanghai]
複製代碼
在指定時間區間內的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: before_route
uri: ${service-url.user-service}
predicates:
- Between=2019-09-24T16:30:00+08:00[Asia/Shanghai], 2019-09-25T16:30:00+08:00[Asia/Shanghai]
複製代碼
帶有指定Cookie的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: ${service-url.user-service}
predicates:
- Cookie=username,macro
複製代碼
使用curl工具發送帶有cookie爲username=macro
的請求能夠匹配該路由。
curl http://localhost:9201/user/1 --cookie "username=macro"
複製代碼
帶有指定請求頭的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: header_route
uri: ${service-url.user-service}
predicates:
- Header=X-Request-Id, \d+
複製代碼
使用curl工具發送帶有請求頭爲X-Request-Id:123
的請求能夠匹配該路由。
curl http://localhost:9201/user/1 -H "X-Request-Id:123"
複製代碼
帶有指定Host的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: ${service-url.user-service}
predicates:
- Host=**.macrozheng.com
複製代碼
使用curl工具發送帶有請求頭爲Host:www.macrozheng.com
的請求能夠匹配該路由。
curl http://localhost:9201/user/1 -H "Host:www.macrozheng.com"
複製代碼
發送指定方法的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: method_route
uri: ${service-url.user-service}
predicates:
- Method=GET
複製代碼
使用curl工具發送GET請求能夠匹配該路由。
curl http://localhost:9201/user/1
複製代碼
使用curl工具發送POST請求沒法匹配該路由。
curl -X POST http://localhost:9201/user/1
複製代碼
發送指定路徑的請求會匹配該路由。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: ${service-url.user-service}/user/{id}
predicates:
- Path=/user/{id}
複製代碼
使用curl工具發送/user/1
路徑請求能夠匹配該路由。
curl http://localhost:9201/user/1
複製代碼
使用curl工具發送/abc/1
路徑請求沒法匹配該路由。
curl http://localhost:9201/abc/1
複製代碼
帶指定查詢參數的請求能夠匹配該路由。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: ${service-url.user-service}/user/getByUsername
predicates:
- Query=username
複製代碼
使用curl工具發送帶username=macro
查詢參數的請求能夠匹配該路由。
curl http://localhost:9201/user/getByUsername?username=macro
複製代碼
使用curl工具發送帶不帶查詢參數的請求沒法匹配該路由。
curl http://localhost:9201/user/getByUsername
複製代碼
從指定遠程地址發起的請求能夠匹配該路由。
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: ${service-url.user-service}
predicates:
- RemoteAddr=192.168.1.1/24
複製代碼
使用curl工具從192.168.1.1發起請求能夠匹配該路由。
curl http://localhost:9201/user/1
複製代碼
使用權重來路由相應請求,如下表示有80%的請求會被路由到localhost:8201,20%會被路由到localhost:8202。
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: http://localhost:8201
predicates:
- Weight=group1, 8
- id: weight_low
uri: http://localhost:8202
predicates:
- Weight=group1, 2
複製代碼
路由過濾器可用於修改進入的HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用。Spring Cloud Gateway 內置了多種路由過濾器,他們都由GatewayFilter的工廠類來產生,下面咱們介紹下經常使用路由過濾器的用法。
給請求添加參數的過濾器。
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: http://localhost:8201
filters:
- AddRequestParameter=username, macro
predicates:
- Method=GET
複製代碼
以上配置會對GET請求添加username=macro
的請求參數,經過curl工具使用如下命令進行測試。
curl http://localhost:9201/user/getByUsername
複製代碼
至關於發起該請求:
curl http://localhost:8201/user/getByUsername?username=macro
複製代碼
對指定數量的路徑前綴進行去除的過濾器。
spring:
cloud:
gateway:
routes:
- id: strip_prefix_route
uri: http://localhost:8201
predicates:
- Path=/user-service/**
filters:
- StripPrefix=2
複製代碼
以上配置會把以/user-service/
開頭的請求的路徑去除兩位,經過curl工具使用如下命令進行測試。
curl http://localhost:9201/user-service/a/user/1
複製代碼
至關於發起該請求:
curl http://localhost:8201/user/1
複製代碼
與StripPrefix過濾器剛好相反,會對原有路徑進行增長操做的過濾器。
spring:
cloud:
gateway:
routes:
- id: prefix_path_route
uri: http://localhost:8201
predicates:
- Method=GET
filters:
- PrefixPath=/user
複製代碼
以上配置會對全部GET請求添加/user
路徑前綴,經過curl工具使用如下命令進行測試。
curl http://localhost:9201/1
複製代碼
至關於發起該請求:
curl http://localhost:8201/user/1
複製代碼
Hystrix 過濾器容許你將斷路器功能添加到網關路由中,使你的服務免受級聯故障的影響,並提供服務降級處理。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
複製代碼
/** * Created by macro on 2019/9/25. */
@RestController
public class FallbackController {
@GetMapping("/fallback")
public Object fallback() {
Map<String,Object> result = new HashMap<>();
result.put("data",null);
result.put("message","Get request fallback!");
result.put("code",500);
return result;
}
}
複製代碼
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: http://localhost:8201
predicates:
- Method=GET
filters:
- name: Hystrix
args:
name: fallbackcmd
fallbackUri: forward:/fallback
複製代碼
RequestRateLimiter 過濾器能夠用於限流,使用RateLimiter實現來肯定是否容許當前請求繼續進行,若是請求太大默認會返回HTTP 429-太多請求狀態。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
複製代碼
/** * Created by macro on 2019/9/25. */
@Configuration
public class RedisRateLimiterConfig {
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
}
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
}
複製代碼
server:
port: 9201
spring:
redis:
host: localhost
password: 123456
port: 6379
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: http://localhost:8201
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1 #每秒容許處理的請求數量
redis-rate-limiter.burstCapacity: 2 #每秒最大處理的請求數量
key-resolver: "#{@ipKeyResolver}" #限流策略,對應策略的Bean
predicates:
- Method=GET
logging:
level:
org.springframework.cloud.gateway: debug
複製代碼
對路由請求進行重試的過濾器,能夠根據路由請求返回的HTTP狀態碼來肯定是否進行重試。
spring:
cloud:
gateway:
routes:
- id: retry_route
uri: http://localhost:8201
predicates:
- Method=GET
filters:
- name: Retry
args:
retries: 1 #須要進行重試的次數
statuses: BAD_GATEWAY #返回哪一個狀態碼須要進行重試,返回狀態碼爲5XX進行重試
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
複製代碼
當調用返回500時會進行重試,訪問測試地址:http://localhost:9201/user/111
能夠發現user-service控制檯報錯2次,說明進行了一次重試。
2019-10-27 14:08:53.435 ERROR 2280 --- [nio-8201-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at com.macro.cloud.controller.UserController.getUser(UserController.java:34) ~[classes/:na]
複製代碼
咱們上次講到使用Zuul做爲網關結合註冊中心進行使用時,默認狀況下Zuul會根據註冊中心註冊的服務列表,以服務名爲路徑建立動態路由,Gateway一樣也實現了該功能。下面咱們演示下Gateway結合註冊中心如何使用默認的動態路由和過濾器。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
複製代碼
server:
port: 9201
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #開啓從註冊中心動態建立路由的功能
lower-case-service-id: true #使用小寫服務名,默認是大寫
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/
logging:
level:
org.springframework.cloud.gateway: debug
複製代碼
在結合註冊中心使用過濾器的時候,咱們須要注意的是uri的協議爲
lb
,這樣才能啓用Gateway的負載均衡功能。
/user
路徑並路由;server:
port: 9201
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: prefixpath_route
uri: lb://user-service #此處須要使用lb協議
predicates:
- Method=GET
filters:
- PrefixPath=/user
discovery:
locator:
enabled: true
eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/
logging:
level:
org.springframework.cloud.gateway: debug
複製代碼
springcloud-learning
├── eureka-server -- eureka註冊中心
├── user-service -- 提供User對象CRUD接口的服務
└── api-gateway -- gateway做爲網關的測試服務
複製代碼
mall項目全套學習教程連載中,關注公衆號第一時間獲取。