spring Cloud-gateWay 進行API網關轉發


1 SpringCloud Gateway 簡介

SpringCloud Gateway 是 Spring Cloud 的一個全新項目,該項目是基於 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技術開發的網關,它旨在為微服務架構提供一種簡單有效的統一的 API 路由管理方式。

SpringCloud Gateway 作為 Spring Cloud 生態系統中的網關,目標是替代 Zuul,在Spring Cloud 2.0以上版本中,沒有對新版本的Zuul 2.0以上最新高性能版本進行集成,仍然還是使用的Zuul 2.0之前的非Reactor模式的老版本。而為了提升網關的性能,SpringCloud Gateway是基於WebFlux框架實現的,而WebFlux框架底層則使用了高性能的Reactor模式通信框架Netty。

Spring Cloud Gateway 的目標,不僅提供統一的路由方式,並且基於 Filter 鏈的方式提供了網關基本的功能,例如:安全,監控/指標,和限流。

提前聲明:Spring Cloud Gateway 底層使用了高性能的通信框架Netty

 

引入依賴:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 需要注冊到eureka -->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

 

2 Spring Cloud Gateway路由配置方式

 

 

yaml文件配置

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        -id: url-proxy-1
          uri: https://blog.csdn.net
          predicates:
            -Path=/csdn

各字段含義如下:

id:我們自定義的路由 ID,保持唯一

uri:目標服務地址

predicates:路由條件,Predicate 接受一個輸入參數,返回一個布爾值結果。該接口包含多種默認方法來將 Predicate 組合成其他復雜的邏輯(比如:與,或,非)。

上面這段配置的意思是,配置了一個 id 為 url-proxy-1的URI代理規則,

路由的規則為:

當訪問地址http://localhost:8080/csdn/1.jsp時,會路由到上游地址https://blog.csdn.net/1.jsp。

 

基於代碼的路由配置方式

轉發功能同樣可以通過代碼來實現,我們可以在啟動類 GateWayApplication 中添加方法 customRouteLocator() 來定制轉發規則。

package com.springcloud.gateway;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
 
@SpringBootApplication
public class GatewayApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
 
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/csdn")
                        .uri("https://blog.csdn.net"))
                .build();
    }
 
}

 

3.Predicate的配置使用

Predicate 就是為了實現一組匹配規則,方便讓請求過來找到對應的 Route 進行處理

 

1.通過請求參數匹配

Query Route Predicate 支持傳入兩個參數,一個是屬性名一個為屬性值,屬性值可以是正則表達式。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            -Query=smile

這樣配置,只要請求中包含 smile 屬性的參數即可匹配路由。

使用 curl 測試,命令行輸入:

curl localhost:8080?smile=x&id=2

經過測試發現只要請求匯總帶有 smile 參數即會匹配路由,不帶 smile 參數則不會匹配。

還可以將 Query 的值以鍵值對的方式進行配置,這樣在請求過來時會對屬性值和正則進行匹配,匹配上才會走路由

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            -Query=keep, pu.

這樣只要當請求中包含 keep 屬性並且參數值是以 pu 開頭的長度為三位的字符串才會進行匹配和路由。

使用 curl 測試,命令行輸入:

curl localhost:8080?keep=pub

測試可以返回頁面代碼,將 keep 的屬性值改為 pubx 再次訪問就會報 404,證明路由需要匹配正則表達式才會進行路由。

 

2.通過 Header 屬性匹配

Header Route Predicate 和 Cookie Route Predicate 一樣,也是接收 2 個參數,一個 header 中屬性名稱和一個正則表達式,這個屬性值和正則表達式匹配則執行。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            - Header=X-Request-Id, \d+

使用 curl 測試,命令行輸入:

curl http://localhost:8080 -H "X-Request-Id:88"

則返回頁面代碼證明匹配成功。將參數-H "X-Request-Id:88"改為-H "X-Request-Id:spring"再次執行時返回404證明沒有匹配。

 

3.通過 Cookie 匹配

Cookie Route Predicate 可以接收兩個參數,一個是 Cookie name ,一個是正則表達式,路由規則會通過獲取對應的 Cookie name 值和正則表達式去匹配,如果匹配上就會執行路由,如果沒有匹配上則不執行。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            - Cookie=sessionId, test

使用 curl 測試,命令行輸入:

curl http://localhost:8080 --cookie "sessionId=test"

則會返回頁面代碼,如果去掉--cookie "sessionId=test",后台匯報 404 錯誤。

 

4.通過 Host 匹配

Host Route Predicate 接收一組參數,一組匹配的域名列表,這個模板是一個 ant 分隔的模板,用.號作為分隔符。它通過參數中的主機地址作為匹配規則。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            - Host=**.baidu.com

使用 curl 測試,命令行輸入:

curl http://localhost:8080 -H "Host: www.baidu.com"

curl http://localhost:8080 -H "Host: md.baidu.com"

經測試以上兩種 host 均可匹配到 host_route 路由,去掉 host 參數則會報 404 錯誤。

 

6 通過請求方式匹配

可以通過是 POST、GET、PUT、DELETE 等不同的請求方式來進行路由。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            - Method=GET

使用 curl 測試,命令行輸入:

# curl 默認是以 GET 的方式去請求

curl http://localhost:8080

測試返回頁面代碼,證明匹配到路由,我們再以 POST 的方式請求測試。

# curl 默認是以 GET 的方式去請求

curl -X POST http://localhost:8080

返回 404 沒有找到,證明沒有匹配上路由

 

7 通過請求路徑匹配

Path Route Predicate 接收一個匹配路徑的參數來判斷是否走路由。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        -id: gateway-service
​          uri: http://ityouknow.com
​          order: 0
​          predicates:
​            -Path=/foo/{segment}

如果請求路徑符合要求,則此路由將匹配,例如:/foo/1 或者 /foo/bar。

使用 curl 測試,命令行輸入:

curl http://localhost:8080/foo/1

curl http://localhost:8080/foo/xx

curl http://localhost:8080/boo/xx

經過測試第一和第二條命令可以正常獲取到頁面返回值,最后一個命令報404,證明路由是通過指定路由來匹配。

 

8 通過請求 ip 地址進行匹配

Predicate 也支持通過設置某個 ip 區間號段的請求才會路由,RemoteAddr Route Predicate 接受 cidr 符號(IPv4 或 IPv6 )字符串的列表(最小大小為1),例如 192.168.0.1/16 (其中 192.168.0.1 是 IP 地址,16 是子網掩碼)。

server:
  port: 8080
spring:
  application:
​    name: api-gateway
  cloud:
​    gateway:
​      routes:
​        - id: gateway-service
​          uri: https://www.baidu.com
​          order: 0
​          predicates:
​            - RemoteAddr=192.168.1.1/24

可以將此地址設置為本機的 ip 地址進行測試。

curl localhost:8080

如果請求的遠程地址是 192.168.1.10,則此路由將匹配。

 

組合使用的例子:

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: gateway-service
          uri: https://www.baidu.com
          order: 0
          predicates:
            - Host=**.foo.org
            - Path=/headers
            - Method=GET
            - Header=X-Request-Id, \d+
            - Query=foo, ba.
            - Query=baz
            - Cookie=chocolate, ch.p

 

predicates的官方參考:
        # 匹配在什么時間之后的 - After=2017-01-20T17:42:47.789-07:00[America/Denver] # 匹配在什么時間之前的 - Before=2017-01-20T17:42:47.789-07:00[America/Denver] # 匹配在某段時間的 - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver] # 匹配cookie名稱為`chocolate`的值要符合`ch.p`正則. - Cookie=chocolate, ch.p # 匹配header為`X-Request-Id`的值要符合`\d+`正則. - Header=X-Request-Id, \d+ # 匹配任意符合`**.somehost.org`與`**.anotherhost.org`正則的網址 - Host=**.somehost.org,**.anotherhost.org # Host還支持模版變量,會保存在`ServerWebExchange.getAttributes()`的 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中,以Map形式存儲 - Host={sub}.myhost.org # 匹配GET方法 - Method=GET # 路徑匹配,與Host一樣支持模版變量,存在URI_TEMPLATE_VARIABLES_ATTRIBUTE中。 - Path=/foo/{segment},/bar/{segment} # 匹配存在baz查詢參數 - Query=baz # 匹配存在foo且符合`ba.`正則 - Query=foo, ba. # 匹配遠程地址 - RemoteAddr=192.168.1.1/24
 
        

 

4.和注冊中心相結合的路由配置方式

在uri的schema協議部分為自定義的lb:類型,表示從微服務注冊中心(如Eureka)訂閱服務,並且進行服務的路由。

一個典型的示例如下:

server:
  port: 8084
spring:
  cloud:
    gateway:
      routes:
      -id: seckill-provider-route
        uri: lb://seckill-provider
        predicates:
        - Path=/seckill-provider/**

      -id: message-provider-route
        uri: lb://message-provider
        predicates:
        -Path=/message-provider/**

application:
  name: cloud-gateway

eureka:
  instance:
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://localhost:8888/eureka/

注冊中心相結合的路由配置方式,與單個URI的路由配置,區別其實很小,僅僅在於URI的schema協議不同。單個URI的地址的schema協議,一般為http或者https協議。

 

5.高級功能-實現熔斷降級

為什么要實現熔斷降級?

在分布式系統中,網關作為流量的入口,因此會有大量的請求進入網關,向其他服務發起調用,其他服務不可避免的會出現調用失敗(超時、異常),失敗時不能讓請求堆積在網關上,需要快速失敗並返回給客戶端,想要實現這個要求,就必須在網關上做熔斷、降級操作。

 

server.port: 8082

spring:
  application:
    name: gateway
  redis:
      host: localhost
      port: 6379
      password: 123456
  cloud:
    gateway:
      routes:
        - id: rateLimit_route
          uri: http://localhost:8000
          order: 0
          predicates:
            - Path=/test/**
          filters:
            - StripPrefix=1
            - name: Hystrix
              args:
                name: fallbackCmdA
                fallbackUri: forward:/fallbackA

hystrix.command.fallbackCmdA.execution.isolation.thread.timeoutInMilliseconds: 5000

這里的配置,使用了兩個過濾器:

(1)過濾器StripPrefix,作用是去掉請求路徑的最前面n個部分截取掉。

StripPrefix=1就代表截取路徑的個數為1,比如前端過來請求/test/good/1/view,匹配成功后,路由到后端的請求路徑就會變成http://localhost:8888/good/1/view。

(2)過濾器Hystrix,作用是通過Hystrix進行熔斷降級

當上游的請求,進入了Hystrix熔斷降級機制時,就會調用fallbackUri配置的降級地址。需要注意的是,還需要單獨設置Hystrix的commandKey的超時時間

fallbackUri配置的降級地址的代碼如下:

package org.gateway.controller;

import org.gateway.response.Response;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FallbackController {

    @GetMapping("/fallbackA")
    public Response fallbackA() {
        Response response = new Response();
        response.setCode("100");
        response.setMessage("服務暫時不可用");
        return response;
    }
}
View Code

 

6.高級功能-分布式限流

這邊就不拓展了

 

 

 

 

 

 

轉載自:https://www.cnblogs.com/crazymakercircle/p/11704077.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM