SpringCloud-Gateway搭建保姆級教程

一、網關介紹

1、什麼是網關?

使⽤服務⽹關作爲接⼝服務的統⼀代理,前端通過⽹關完成服務的統⼀調⽤

2、⽹關可以⼲什麼?

路由:接⼝服務的統⼀代理,實現前端對接⼝服務的統⼀訪問
過濾:對⽤戶請求進⾏攔截、過濾(⽤戶鑑權)、監控
限流:限制⽤戶的訪問流量

3、常⽤的⽹關

Nginx
Spring Cloud Netflix zuul
Spring Cloud Gateway

二、使⽤Nginx實現⽹關服務

Nginx通常被⽤作應⽤服務器⽹關,服務⽹關通常使⽤zuul或者gateway

三、使用Zuul實現網關服務

四、使用Gateway實現網關服務

1、搭建gateway服務器

創建SpringBoot應⽤,添加gateway依賴

2、配置路由規則

application.yml
server:
  port: 9999
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        # 配置api-service1路由規則
        - id: api-service1
          uri: 'http://localhost:8001'
          predicates:
            - Path=/product/**
        # 配置api-service2路由規則
        - id: api-service2
          uri: 'http://localhost:8002'
          predicates:
            - Path=/order/**

五、Gateway⼯作原理

1、名詞解釋

Route: 路由是⽹關的基本組成部分,它是由id、⽬標uri、斷⾔組成,如果斷⾔爲true,則匹配該路由,轉向到當前路由的URI
Predicate:斷⾔,⽤戶請求的匹配規則
Filter:過濾器,⽤於對請求進⾏前置、後置處理(可以在⽹關實現對請求或相應的加⼯處理)

2、Gateway⼯作流程圖

六、Predicate斷⾔

SpringCloud Gateway提供了多種斷⾔匹配的⽅式:
  • After
  • Before
  • Between
  • Cookie
  • Header
  • Host
  • Method
  • Path
  • Query
  • RemoteAddr
  • Weight

1、Path

根據請求路徑的正則匹配
spring:
  application: null
  name: gateway-server
  cloud: null
  gateway: null
  routes:
    - id: aaa
      uri: 'http://localhost:8001'
      predicates:
        - Path=/product/**
    - id: bbb
      uri: 'http://localhost:8002'
      predicates:
        - Path=/order/**

2、Query

根據請求攜帶的參數匹配路由
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        - id: aaa
          uri: 'http://localhost:8001'
          predicates:
            # 如果請求url中帶有name參數 ---> http://localhost:8001
            - Query=name
        - id: bbb
          uri: 'http://localhost:8002'
          predicates:
            #如果請求url中帶有pwd參數 ---> http://localhost:8002
            - Query=pwd

3、Header 

根據Header中攜帶的參數匹配
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        - id: aaa
          uri: 'http://localhost:8001'
          predicates:
            - Header=token
        - id: bbb
          uri: 'http://localhost:8002'
          predicates:
            - 'Header=aa,haha'

七、過濾器

1、Gateway內置⽹關過濾器

gateway⽹關可以對⽤戶的請求和響應進⾏處理,gateway提供了多個內置的過濾器,
不同的過濾器可以完成不同的請求或者響應的處理
1. AddRequestHeader 在請求頭中添加參數
2. AddRequestParameter 添加請求參數
3. AddResponseHeader
4. The DedupeResponseHeader GatewayFilter Factory
5. The Hystrix GatewayFilter Factory
6. Spring Cloud CircuitBreaker GatewayFilter Factory
7. The FallbackHeaders GatewayFilter Factory
8. The MapRequestHeader GatewayFilter Factory
9. The PrefixPath GatewayFilter Factory
10. The PreserveHostHeader GatewayFilter Factory
11. The RequestRateLimiter GatewayFilter Factory
12. The RedirectTo GatewayFilter Factory
13. The RemoveRequestHeader GatewayFilter Factory
14.  RemoveResponseHeader GatewayFilter Factory
15.  The RemoveRequestParameter GatewayFilter Factory
16.  The RewritePath GatewayFilter Factory
17.  RewriteLocationResponseHeader GatewayFilter Factory
18.  The RewriteResponseHeader GatewayFilter Factory
19.  The SaveSession GatewayFilter Factory
20.  The SecureHeaders GatewayFilter Factory
21.  The SetPath GatewayFilter Factory
22.  The SetRequestHeader GatewayFilter Factory
23.  The SetResponseHeader GatewayFilter Factory
24.  The SetStatus GatewayFilter Factory
25.  The StripPrefix GatewayFilter Factory
26.  The Retry GatewayFilter Factory
27.  The RequestSize GatewayFilter Factory
28.  The SetRequestHostHeader GatewayFilter Factory
29.  Modify a Request Body GatewayFilter Factory
30.  Modify a Response Body GatewayFilter Factory
31.  Default Filters
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        - id: aaa
          uri: 'http://localhost:8001'
          predicates:
            - Path=/red/aaa/product/**
      filters:
        - 'AddRequestHeader=token,wahahaawahaha'
        - 'AddRequestParameter=username, ergou'
        - SetStatus=404
        - StripPrefix=2

2、⾃定義服務過濾器

2.1、創建⽹關過濾器 - 實現GatewayFilter

1、實現GatewayFilter, Ordered

public class MyFilter01 implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); System.out.println("---------------⾃定義過濾器"); return chain.filter(exchange); }
@Override
public int getOrder() { return 0; } }

2、配置過濾器

@Configuration
public class GatewayConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){ System.out.println("-----------------------init"); RouteLocator routeLocator = builder.routes().route( r->     r.path("/product/**") // predicates      .filters(f->f.filters( new MyFilter01() )) //filters     .uri("http://localhost:8001") //uri   ).build(); return routeLocator; }
}

2.2、創建⽹關過濾器 - 繼承AbstractNameValueGatewayFilterFactory

相當於擴展Gateway內置的⽹關過濾器
/**
* 創建⼀個類繼承AbstractNameValueGatewayFilterFactory,類名必須以GatewayFilterFactory結尾,類名前⾯的部分即爲當前⾃定義⽹關過濾器的 名字
* 添加@Component註解,註冊到Spring容器
*/
@Component
public class MyFilterGatewayFilterFactory extends
AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        System.out.println("name:"+config.getName());
        System.out.println("value:"+config.getValue());
        //創建⾃定義⽹關過濾器並返回
        GatewayFilter gatewayFilter = new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~⾃定義⽹關過濾器");
                return chain.filter(exchange);
            }
        };
        return gatewayFilter;
    }
}
配置:
spring:
  application:
    name: gateway-server
  cloud:
    gateway:
      routes:
        - id: bbb
          uri: 'http://localhost:8002'
          predicates:
            - Path=/order/**
      filters:
        - 'MyFilter=aa,bb'

3、全局過濾器

上述我們講到的過濾器,都是配置在某個路由/服務中,我們稱之爲 ⽹關服務過濾器 ,
Gateway提供了內置的全局過濾器,會攔截過濾所有到達⽹關服務器的請求。
內置的全局過濾器默認⽣效,⽆需開發者⼲預。
根據業務的需求我們也可以⾃定義全局過濾器以實現對所有⽹關請求的攔截和處理。
 
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("----------------------------------------------MyGlobalFilter"); List<String> list = exchange.getRequest().getHeaders().get("token"); if (list != null && list.size()>0){ String token = list.get(0); System.out.println("token:"+token); return chain.filter(exchange); } else{ //如果沒有token,或者token過期 ServerHttpResponse response = exchange.getResponse(); //設置響應頭 response.getHeaders().add("ContentType","application/json;charset=utf-8"); //設置狀態碼 response.setStatusCode(HttpStatus.UNAUTHORIZED); // 封裝響應數據 String str = ""; DataBuffer dataBuffer = response.bufferFactory().wrap(str.getBytes()); return response.writeWith(Mono.just(dataBuffer)); } }
@Override
public int getOrder() { return 0; } }

八、Gateway動態路由配置

如果在Gateway⽹關的路由配置中,直接將服務的ip port配置進去,將導致:
1.如果服務的地址變更,必須要重新配置gateway的路由規則
2.如果服務採⽤集羣部署,則不能實現負載均衡

 

1、Gateway服務器添加eureka-server依賴

<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2、配置⽹關路由

application.yml
server:
  port: 9999
spring:
  application:
    name: gateway-server
  main:
    web-application-type: reactive
  cloud:
    gateway:
      routes:
        - id: aaa
          uri: 'lb://api-service1'
          predicates:
            - Path=/product/**
        - id: bbb
          uri: 'lb://api-service2'
          predicates:
            - Path=/order/**
eureka:
  client:
    service-url:
      defaultZone: 'http://localhost:8761/eureka'

九、⽹關限流

1、⽹關限流介紹

服務的統⼀訪問
使⽤過濾器實現鑑權
使⽤⽹關實現限流:通過限制⽤戶的請求進⼊到服務中,有效控制應⽤系統的QPS,達到保護系統的⽬的
在互聯⽹應⽤的⽣產環境中,可以由於⽤戶增⻓超過預期、競爭對⼿惡意請求等外界的原因都有可能導致服務器⽆法處理超預期的⾼併發請求導致服務器宕機

2、⽹關限流的常⻅算法

2.1、計數器算法

就是通過記錄在單位時間請求的數量,在這個時間週期內達到設置定值之後就拒絕後續請求的進⼊。
缺點:如果⽤戶請求頻率不均勻,有導致短時間、⾼併發的⻛險

2.2、漏桶算法

就是通過控制“漏桶”流出的速率以限制到達服務的⽤戶流量
缺點:⽹關會承載⽐較⼤的壓⼒

2.3、令牌桶算法

就是所有進⼊⽹關的請求必須從令牌桶中得到令牌纔可以進⾏服務調⽤,我們可以通過控制令牌桶的容量、令牌的產⽣速率達到控制⽤戶流量的⽬的

3、Gateway⽹關限流

Gateway是基於令牌桶算法,使⽤redis作爲“桶”結合過濾器實現了⽹關限流。

 

1、添加依賴
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
   <version>2.9.0</version>
</dependency>

2、配置keyResolver

@Configuration
public class AppConfig {
    @Bean
    public KeyResolver keyResolver() {
        //http://localhost:9999/order/query?user=1
        //使⽤請求中的user參數的值作爲令牌桶的key
        //return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
    }
}

3、配置服務的限流規則

server:
  port: 9999
spring:
  application:
    name: gateway-server
  main:
    web-application-type: reactive
  cloud:
    gateway:
      routes:
        - id: aaa
          uri: 'lb://api-service1'
          predicates:
            - Path=/product/**
        - id: bbb
          uri: 'lb://api-service2'
          predicates:
            - Path=/order/**
      filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 1  #令牌桶每s的填充速度
            redis-rate-limiter.burstCapacity: 2  #令牌桶容量
            redis-rate-limiter.requestedTokens: 1  #每個請求消耗多少個令牌
            key-resolver: '#{@keyResolver}'        #令牌桶key生成
  redis:
    host: 47.96.11.185
    port: 7001
    password: qfedu123
    database: 0
    lettuce:
      pool:
        max-active: 10
        max-wait: 1000
        max-idle: 5
        min-idle: 3
eureka:
  client:
    service-url:
      defaultZone: 'http://localhost:8761/eureka'

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章