這是我參與更文挑戰的第1天,活動詳情查看: 更文挑戰html
本文正在參加「Java主題月 - Java 開發實戰」,詳情查看 活動連接java
分佈式系列之網關zuul包攬全局--不再用東拼西湊各個接口啦web
gateway的誕生是由於zuul2.0一直跳票,既然這樣gateway能夠說是zuul的替代品。既然是替代品功能確定是包含了zuul的。redis
SpringCloud Gateway是基於webflux的非阻塞式的網關。 因此gateway的環境要求 Springboot 2.x+、spring webflux、project reactor算法
由於是非阻塞式,因此和咱們以前的阻塞式框架會有所不一樣。spring
名詞 | 解釋 |
---|---|
Route | 網關的基本組成部分。它由一個ID、一個目標URI、一組謂詞和一組過濾器定義。若是聚合謂詞爲真,則匹配路由 |
Predicate | 這是一個Java 8函數謂詞。輸入類型是Spring Framework serverwebeexchange。這容許您匹配HTTP請求中的任何內容,好比頭或參數 |
Filter | 這些是使用特定工廠構造的GatewayFilter實例。發送下游請求以前或以後修改請求和響應 |
點我官網快速開始api
新建模塊geteway 並制定端口9091數組
引入座標安全
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
複製代碼
spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
複製代碼
接口測試 : 咱們訪問http://localhost:9091/payment/get/1
會出現8001payment的信息
下面咱們詳細來看看gateway的路由規則
Springcloud網關匹配路由做爲Spring WebFlux HandlerMapping基礎設施的一部分。Spring Cloud Gateway包括許多內置的路由前置工廠。全部這些都匹配HTTP請求的不一樣屬性。咱們能夠將多個路由謂詞工廠與邏輯和語句組合在一塊兒
PathRoutePredicateFactory
來實現的spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
複製代碼
spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- Query=green
複製代碼
http://localhost:9091/payment/get/1
接口將訪問不了數據,必須添加green參數 http://localhost:9091/payment/get/1?green
光有參數仍是不行,加入咱們要求green參數必須是數組。咱們能夠以下配置
spring:
cloud:
gateway:
routes:
- id: route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- Query=green,\d+
複製代碼
http://localhost:9091/payment/get/1?green=123s
不能訪問 , http://localhost:9091/payment/get/1?green=123
則能夠spring:
cloud:
gateway:
routes:
- id: after_route
uri: http://localhost:8001
predicates:
- Path=/payment/get/**
- Query=green,\d+
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
複製代碼
- RemoteAddr=10.0.20.132/140
複製代碼
10.0.20.132-10.0.20.140
這個段的ip均可以訪問- Cookie=zxhtom, hello
複製代碼
在zuul中整合服務發現後有默認的路由規則的。一樣的gateway也能夠接入服務發現這裏仍是以eureka爲列。
這裏有關服務發現的配置我就再也不贅述了。在eureka專題已經介紹了,在hystrix、zuul等專題頁有相關的配置,我就直接貼出gateway的開啓配置
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
複製代碼
http://localhost:9091/cloud-payment-service/payment/get/2
還記得咱們在zuul專題中實現了默認路由轉發規則嗎,就是將CLOUD-PAYMENT-SERVICE
、CLOUD-ORDER-SERVICE
這些微服務默認代理爲payment
、order
的服務前綴。在gateway中他也爲咱們提供了相同的功能即服務轉發。可是他是針對具體的微服務的。咱們能夠經過自定義全局過濾器來實現zuul中的功能。下面咱們來試試經過RewiritePathGatewayFilterFactory
實現它
爲了突出核心配置,這裏我只放部分配置,須要完整的能夠參考上下文。或者直接看源碼。源碼會在文章末尾放出
- id: order
uri: lb://CLOUD-ORDER-SERVICE
predicates:
- Query=green
filters:
- RewritePath=/order/(?<segment>.*), /$\{segment}
複製代碼
相似而又不一樣的是,PrefixPathGatewayFilterFactory
是在咱們匹配接口上統一加上前綴。好比以下配置- id: pre_route
uri: http://localhost:8001
predicates:
- Path=/getTimeOut/**
filters:
- PrefixPath=/payment
複製代碼
http://localhost:9091/getTimeOut/123
訪問這個接口的時候,咱們首先經過routes 中配置匹配到pre_route
而後在接口前添加payment而後路由到真實服務上。 這裏須要注意的是咱們的匹配是從上至下的因此咱們配置的時候注意下順序- id: pre_route
uri: http://localhost:8001
predicates:
- Path=/zxhtom/**
filters:
- StripPrefix=2
複製代碼
http://localhost:9091/zxhtom/lqj/payment/getTimeOut/123
實際上會轉發到http://localhost:8001/payment/getTimeOut/123
上。注意咱們uri的協議,若是是lb表示是服務發現。這裏咱們配置的是單節點- id: pre_route3
uri: http://localhost:8001
predicates:
- Path=/hello/{segment}
filters:
- SetPath=/payment/get/{segment}
複製代碼
http://localhost:9091/hello/123
轉發到http://localhost:8081/payment/get/123
上RewritePathGatewayFilterFactory
這些過濾器在配置的時候是配置成RewritePath
後面的GatewayFilterFactory
是沒有的。@Component
public class LoginPathGatewayFilterFactory extends AbstractGatewayFilterFactory<LoginPathGatewayFilterFactory.Config> {
public LoginPathGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchage,chain)->{
String userName = config.getUserName();
String password = config.getPassword();
String requestUserName = exchage.getRequest().getQueryParams().getFirst("userName");
String requestPassword = exchage.getRequest().getQueryParams().getFirst("password");
if (userName.equals(requestUserName) && password.equals(requestPassword)) {
return chain.filter(exchage);
} else {
throw new RuntimeException("用戶名錯誤密碼。。。。");
}
};
}
public static class Config {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public Config setUserName(String userName) {
this.userName = userName;
return this;
}
public String getPassword() {
return password;
}
public Config setPassword(String password) {
this.password = password;
return this;
}
}
}
複製代碼
- id: pre_route4
uri: http://localhost:8001
predicates:
- Path=/login/{segment}
filters:
- name: LoginPath
args:
userName: zxhtom
password: test
- SetPath=/payment/get/{segment}
複製代碼
GatewayFilter
對象。實際上GatewayFilter
纔是真正參與過濾的對象。@Component
public class CustomLoginGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("我進過濾器啦。。。");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
複製代碼
@Configuration
public class RouteConfig {
@Bean
public RouteLocator customRouteLocator(CustomLoginGatewayFilter customLoginGatewayFilter,RouteLocatorBuilder builder) {
return builder.routes()
.route("path_route", r -> r.path("/baidu")
.uri("https://www.baidu.com")
.filter(customLoginGatewayFilter))
.build();
}
}
複製代碼
WebsocketRoutingFilter
是gateway內置的,他的實現和網關過濾器其中一種方式同樣。@Slf4j
@Component
public class GlobalCustomRoutingFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("我是全局過濾器。。。。。。");
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 0;
}
}
複製代碼
關於限流筆者以前經過redis分別實現目前主流的四種限流算法。有興趣的能夠閱讀下,閱讀結束別忘記回到本文繼續觀看gateway哦。別走太遠!!!
上面咱們主要在介紹gateway
的用法即合成方向。可是做爲網站的門戶性接口流量比其餘服務都大的不少。其餘服務正常狀況咱們會依賴於hystrix
來實現對服務的降級等操做。一樣咱們也能夠在網關層面上加入hystrix來實現服務的高可用。 可是除了hystrix之外, gateway
自己內置了限流算法。下面咱們來簡單實現下限流。
提到網關咱們就必定繞不開限流。網關的做用就是代理可是並非沒有條件的任性代理。爲何保護咱們的模塊在網關中會對下游服務進行限流。有些接口處於安全和穩定考慮都會限制流量的
gateway實現限流也很簡單。只須要咱們引入redis相關模塊在使用內置過濾器就能夠了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
複製代碼
@Component
public class HostAddrKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
//根據服務地址限流
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
@Bean
KeyResolver apiKeyResolver() {
//按URL限流
return exchange -> Mono.just(exchange.getRequest().getPath().toString());
}
@Bean
KeyResolver userKeyResolver() {
//按用戶限流
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userName"));
}
}
複製代碼
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
複製代碼
@RestController
@RequestMapping("/fallback")
public class FallbackController {
@RequestMapping("")
public String fallback(){
return "error";
}
}
複製代碼