使用Spring Cloud Gateway構建微服務網關

使用Spring Cloud Gateway構建微服務網關

Spring Cloud GateWay介紹

微服務架構中,前端(APP或Web端)需要同各個微服務進行交互,因實際部署時不同服務可能在不同機器各個服務甚至還有集羣,這無形中增加了客戶端調用微服務的複雜程度。如一個添加一樣商品到購物車可能涉及到用戶服務、商品服務、購物車服務等,如果直接由客戶端去對應的服務地址去調用可能涉及到下面的問題:

  • 客戶端會多次請求不同的微服務,增加了客戶端的複雜性。
  • 存在跨域請求,在一定場景下處理相對複雜。
  • 認證複雜,每個服務都需要獨立認證。
  • 難以重構,隨着項目的迭代,可能需要重新劃分微服務。例如,可能將多個服務合併成一個或者將一個服務拆分成多個。如果客戶端直接與微服務通信,那麼重構將會很難實施。
  • 某些微服務可能使用了防火牆 / 瀏覽器不友好的協議,直接訪問會有一定的困難

爲了解決上述問題,API網關應運而生。所有的服務都經過網關進行路由,這樣客戶端對接API網關,API網關對請求進行路由即可訪問對應的微服務。由於各個服務都由網關代理,認證、監控、鑑權、日誌等都可以在網關上做,總的來說,使用API網關優點如下:

  • 易於監控。可以在網關收集監控數據並將其推送到外部系統進行分析。
  • 易於認證。可以在網關上進行認證,然後再將請求轉發到後端的微服務,而無須在每個微服務中進行認證。
  • 減少了客戶端與各個微服務之間的交互次數。
    目前網關產品有很多,如Zuul、Kong、Api Umbrella等。由於Netflix宣佈閉源,Spring Cloud也推出了自己的網關SPring Cloud Gateway來代替Zuul,本文就以Spring Cloud Gateway爲例,學習API網關的使用。

網關服務搭建

筆者的理解中API網關在系統中的架構如下所示:
在這裏插入圖片描述
API網關負責接收客戶端的請求,在經過認證、鑑權、限流等功能後轉發到對應的微服務。在API網關可以實現單點登錄功能從而解決各個服務認證方式不同的問題。接下來搭建簡單的網關服務加深理解

新建項目

誰用http://start.spring.io搭建項目。可參考使用IDEA創建SpringBoot項目

引入依賴

在build.gradle中添加下面依賴

 compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-gateway'
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-openfeign'
    compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-hystrix'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux'
//    compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis-reactive'
    compile group: 'org.springframework.boot', name: 'spring-boot-autoconfigure'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-logging'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-aop'
    compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator'
    compile group: 'org.springframework.boot', name: 'spring-boot-devtools'

其他代碼可以見最後的代碼倉庫,爲了方便閱讀這裏不貼其他無用代碼

配置路由

添加一個測試的路由,訪問網關的/test,自動路由到百度

@Configuration
public class Router1Config {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                //簽發服務路由
                .route("license_route", r -> r.path("/test")
                        .uri("http://www.baidu.com"))
                .build();
    }
}

在瀏覽器訪問http://127.0.0.1:8900/test,顯示結果如下:
在這裏插入圖片描述
從瀏覽器的network可以看出,訪問http://127.0.0.1:8900/test被重定向到了百度的頁面。這裏簡單的網關功能已實現。接下來則實現集成Nacos並通過API網關訪問微服務

Spring Cloud GateWay集成Nacos

  • 添加Nacos依賴
    //Spring Cloud Alibaba 基礎框架
    //服務註冊與發現
    implementation "com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:${springCloudAlibabaVersion}"
    //分佈式配置中心
    implementation "com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config:${springCloudAlibabaVersion}"

  • 添加配置
    在bootstrap.yml中添加配置
spring:
  application:
    name: api-gateway

  cloud:
    nacos:
      config:
        server-addr: 192.168.23.100:8848
        file-extension: yaml
        enabled: true
      discovery:
        server-addr: 192.168.23.100:8848
        enabled: true
  • 啓動服務
    登錄Nacos管理頁面,可以看到網關也已經註冊到了Nacos
    在這裏插入圖片描述

通過API網關訪問微服務

  • 啓動之前文章中的服務
    分別啓動nacos-provider-demonacos-consumer-demo,可以看到這兩個服務業註冊成功
    在這裏插入圖片描述
  • 添加路由,訪問微服務
    添加如下路由
@Configuration
public class RouterConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                //服務路由,lb表示註冊中心的服務
                .route("service_route", r -> r.path("/sayHi/*")
                        .uri("lb://nacos-provider-demo"))
                .build();
    }
}

啓動服務,網關服務,訪問http://127.0.0.1:9000/sayHi/xuda結果如下,成功調用到了微服務的接口:
在這裏插入圖片描述

關於Spring Cloud Gateway的路由知識可參考Spring Cloud GateWay 路由轉發規則介紹

實現網關認證

API網關的重要特性之一就是可以實現集中認證,這裏實現要給簡單的認證功能。如果請求的header中包含user_name字段即算作認證成功(這裏只是一個示例,具體的認證過程由項目決定)。
這裏需要用到過濾器,filter主要可分爲兩種,一種GlableFilter一種GateWayFilter。GlableFilter是全局filter對所有的路由都會經過這個過濾器,GateWayFilter粒度更細可以針對不同的路由做過濾。具體的過濾器區別可參考[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UOyTAsAi-1576386805878)(https://blog.csdn.net/forezp/article/details/85057268)]
接下來使用全局過濾器實現一個簡單的認證功能。下面只是一部分代碼,具體的代碼可以見最後的倉庫


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        if (isSkip(path)) {
            return chain.filter(exchange);
        }
        ServerHttpResponse resp = exchange.getResponse();
        String username = exchange.getRequest().getHeaders().getFirst(TokenConstant.USER_NAME);
        LOGGER.info("進入認證步驟");
        if (StringUtils.isBlank(username)) {
            return unAuth(resp, "認證失敗,缺少用戶名", HttpStatus.UNAUTHORIZED);
        }

        return chain.filter(exchange);
    }

先使用不帶請求頭的模擬認證,結果如下:
在這裏插入圖片描述
再使用帶請求頭的模擬認證,結果如下:
在這裏插入圖片描述

請求成功,這樣就實現了模擬認證的功能。

代碼倉庫

github鏈接

發佈了39 篇原創文章 · 獲贊 24 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章