前段時間剛剛發佈了Spring Boot 2正式版,Spring Cloud Gateway基於Spring Boot 2,是Spring Cloud的全新項目,該項目提供了一個構建在Spring 生態之上的API網關,包括:Spring 5,Spring Boot 2和Project Reactor。 Spring Cloud Gateway旨在提供一種簡單而有效的途徑來發送API,併爲他們提供橫切關注點,例如:安全性,監控/指標和彈性。當前最新的版本是v2.0.0.M8
,正式版最近也會到來。java
Spring Cloud Gateway的特徵:git
Zuul基於servlet 2.5(使用3.x),使用阻塞API。 它不支持任何長鏈接,如websockets。而Gateway創建在Spring Framework 5,Project Reactor和Spring Boot 2之上,使用非阻塞API。 Websockets獲得支持,而且因爲它與Spring緊密集成,因此將會是一個更好的開發體驗。github
筆者最近研讀了Spring Cloud Gateway的源碼,大部分功能的實現也寫了源碼分析的文章,但畢竟正式版沒有發佈,本文算是一篇入門實踐,展現經常使用的幾個功能,期待最近的正式版本發佈。web
示例啓動兩個服務:Gateway-Server和user-Server。模擬的場景是,客戶端請求後端服務,網關提供後端服務的統一入口。後端的服務都註冊到服務發現Consul(搭建zk,Eureka均可以,筆者比較習慣使用consul)。網關經過負載均衡轉發到具體的後端服務。spring
用戶服務註冊到Consul上,並提供一個接口/test
。後端
須要的依賴以下:安全
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
複製代碼
spring:
application:
name: user-service
cloud:
consul:
host: 192.168.1.204
port: 8500
discovery:
ip-address: ${HOST_ADDRESS:localhost}
port: ${SERVER_PORT:${server.port}}
healthCheckPath: /health
healthCheckInterval: 15s
instance-id: user-${server.port}
service-name: user
server:
port: 8005
management:
security:
enabled: false
複製代碼
@SpringBootApplication
@RestController
@EnableDiscoveryClient
public class GatewayUserApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayUserApplication.class, args);
}
@GetMapping("/test")
public String test() {
return "ok";
}
}
複製代碼
暴露/test
接口,返回ok便可。微信
網關服務提供多種路由配置、路由斷言工廠和過濾器工廠等功能。websocket
須要引入的依賴:app
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
//依賴於webflux,必須引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-core</artifactId>
</dependency>
//服務發現組件,排除web依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>2.0.0.M6</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
//kotlin依賴
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
<optional>true</optional>
</dependency>
複製代碼
如上引入了kotlin相關的依賴,這裏須要支持kotlin的路由配置。Spring Cloud Gateway的使用須要排除web相關的配置,引入的是webflux的引用,應用啓動時會檢查,必須引入。
路由斷言工廠有多種類型,根據請求的時間、host、路徑、方法等等。以下定義的是一個基於路徑的路由斷言匹配。
@Bean
public RouterFunction<ServerResponse> testFunRouterFunction() {
RouterFunction<ServerResponse> route = RouterFunctions.route(
RequestPredicates.path("/testfun"),
request -> ServerResponse.ok().body(BodyInserters.fromObject("hello")));
return route;
}
複製代碼
當請求的路徑爲/testfun
時,直接返回ok的狀態碼,且響應體爲hello
字符串。
網關常常須要對路由請求進行過濾,進行一些操做,如鑑權以後構造頭部之類的,過濾的種類不少,如增長請求頭、增長請求參數、增長響應頭和斷路器等等功能。
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
//@formatter:off
return builder.routes()
.route(r -> r.path("/image/webp")
.filters(f ->
f.addResponseHeader("X-AnotherHeader", "baz"))
.uri("http://httpbin.org:80")
)
.build();
//@formatter:on
}
複製代碼
如上實現了當請求路徑爲/image/webp
時,將請求轉發到http://httpbin.org:80
,並對響應進行過濾處理,增長響應的頭部X-AnotherHeader: baz
。
上面兩小節屬於API自定義路由,還能夠經過配置進行定義:
spring:
cloud:
gateway:
locator:
enabled: true
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
routes:
# =====================================
- id: default_path_to_http
uri: blueskykong.com
order: 10000
predicates:
- Path=/**
複製代碼
如上的配置定義了路由與過濾器。全局過濾器將全部的響應加上頭部X-Response-Default-Foo: Default-Bar
。定義了id爲default_path_to_http
的路由,只是優先級比較低,當該請求都不能匹配時,將會轉發到blueskykong.com
。
Spring Cloud Gateway可使用kotlin自定義路由:
@Configuration
class AdditionalRoutes {
@Bean
fun additionalRouteLocator(builder: RouteLocatorBuilder): RouteLocator = builder.routes {
route(id = "test-kotlin") {
path("/image/png")
filters {
addResponseHeader("X-TestHeader", "foobar")
}
uri("http://httpbin.org:80")
}
}
}
複製代碼
當請求的路徑是/image/png
,將會轉發到http://httpbin.org:80
,並設置了過濾器,在其響應頭中加上了X-TestHeader: foobar
頭部。
與服務註冊於發現組件進行結合,經過serviceId轉發到具體的服務實例。在前面的配置已經引入了相應的依賴。
@Bean
public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
}
複製代碼
將DiscoveryClient
注入到DiscoveryClientRouteDefinitionLocator
的構造函數中,關於該路由定義定位器,後面的源碼分析會講解,此處不展開。
spring:
cloud:
gateway:
locator:
enabled: true
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
routes:
# =====================================
- id: service_to_user
uri: lb://user
order: 8000
predicates:
- Path=/user/**
filters:
- StripPrefix=1
複製代碼
上面的配置開啓了DiscoveryClient
定位器的實現。路由定義了,全部請求路徑以/user
開頭的請求,都將會轉發到user
服務,並應用路徑的過濾器,截取掉路徑的第一部分前綴。即訪問/user/test
的實際請求轉換成了lb://user/test
。
還能夠配置websocket的網關路由:
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
routes:
- id: websocket_test
uri: ws://localhost:9000
order: 9000
predicates:
- Path=/echo
複製代碼
啓動一個ws服務端wscat --listen 9000
,將網關啓動(網關端口爲9090),進行客戶端鏈接便可wscat --connect ws://localhost:9090/echo
。
上述實現的功能,讀者能夠自行下載源碼進行嘗試。筆者這裏只展現訪問用戶服務的結果:
X-Response-Default-Foo: Default-Bar
在本文中,咱們探討了屬於Spring Cloud Gateway的一些功能和組件。 這個新的API提供了用於網關和代理支持的開箱即用工具。期待Spring Cloud Gateway 2.0正式版。