微服務之服務網關

来源:https://www.cnblogs.com/sss4/archive/2022/06/27/16414983.html
-Advertisement-
Play Games

前言 在微服務架構中,1個系統會被拆分為了很多個微服務。 如果每1個微服務都直接對外暴露出來,讓用戶直接訪問這些微服務; 那麼如何對用戶的身份和許可權進行鑒定?如何對微服務中的訪問流量進行限流? 此時我們需要1個統一的入口(網關服務)以上問題將迎刃而解; 一、服務網關(Gateway)簡介 微服務的網 ...


前言

在微服務架構中,1個系統會被拆分為了很多個微服務。

如果每1個微服務都直接對外暴露出來,讓用戶直接訪問這些微服務;

那麼如何對用戶的身份和許可權進行鑒定?如何對微服務中的訪問流量進行限流?

此時我們需要1個統一的入口(網關服務)以上問題將迎刃而解;

 

 

一、服務網關(Gateway)簡介

微服務的網關=路由轉發+過濾器

如果沒有網關的存在,我們只能在客戶端記錄每個微服務的地址,然後分別去調用。

以上架構,會存在著諸多的問題:

  • 客戶端多次請求不同的微服務,增加客戶端代碼或配置編寫的複雜性

  • 認證複雜,每個服務都需要獨立認證。

  • 存在跨域請求,在一定場景下處理相對複雜。

上面的這些問題可以藉助API網關來解決。所謂的API網關,就是指系統的統一入口。它封裝了應用程式的內部結構,為客戶端提供統一服務。

一些與業務本身功能無關的公共邏輯可以在這裡實現,諸如認證、鑒權、監控、路由轉發等等。

添加上API網關之後,系統的架構圖變成瞭如下所示:

Spring Cloud Gateway旨在為微服務架構提供一種簡單有效的統一的 API路由管理方式。

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

 

微服務網關的作用

  • 提供了統一訪問入口,降低了服務受攻擊面
  • 提供了統一跨域解決方案
  • 提供了統一日誌記錄操作,可以進行統一監控
  • 提供了統一許可權認證支持
  • 提供了微服務限流功能,可以保護微服務,防止雪崩效應發生

 

二、Gateway搭建

1.創建1個api-gateway模塊

 

2.pom依賴

我們使用的網關產品為spring-cloud框架提供的gateway;

服務網關需要調用服務註冊中心(Nacos)獲取服務提供者的調用地址;

<dependencies>
        <!--引入gateway網關-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        
        <!--Nacos服務發現依賴-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

2.創建啟動類

package com.zhanggen.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

 

3.添加配置文件(application.yaml)

路由(Route) 是 gateway 中最基本的組件之一,表示一個具體的路由信息載體。主要定義了下麵的幾個信息:

  • id,路由標識符,區別於其他 Route。

  • uri,路由指向的目的地 uri,即客戶端請求最終被轉發到的微服務。

  • predicate,斷言的作用是進行條件判斷,只有斷言都返回真,才會真正的執行路由。

  • filter,過濾器用於修改請求和響應信息。

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 路由數組[路由 就是指定當請求滿足什麼條件的時候轉到哪個微服務]
        - id: user-service-route # 當前路由的標識, 要求唯一
          uri: lb://user-service # 請求要轉發到的地址
          predicates: # 斷言(就是路由轉發要滿足的條件)
            - Path=/user/** # 當請求路徑滿足Path指定的規則時,才進行路由轉發

 

4.測試網關路由轉發功能

啟動項目,並通過網關去訪問用戶微服務,現請求流程如下

 

 

三、斷言(理解)

斷言就是1刀切,只有當前這1個條件判斷成功才能進行路由轉發,只有斷言都返回真,才會真正的執行路由。

1.基於Datetime類型的斷言

# AfterRoutePredicateFactory:   接收一個日期參數,判斷請求日期是否晚於指定日期
# BeforeRoutePredicateFactory:  接收一個日期參數,判斷請求日期是否早於指定日期
# BetweenRoutePredicateFactory: 接收兩個日期參數,判斷請求日期是否在指定時間段內
- After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]

2.基於遠程地址的斷言

# RemoteAddrRoutePredicateFactory:接收一個IP地址段,判斷請求主機地址是否在地址段中
- RemoteAddr=192.168.1.1/24

3.基於Cookie的斷言

# CookieRoutePredicateFactory:接收兩個參數,cookie 名字和一個正則表達式。 判斷請求cookie是否具有給定名稱且值與正則表達式匹配。
- Cookie=chocolate, ch. 

4.基於Header的斷言

# HeaderRoutePredicateFactory:接收兩個參數,標題名稱和正則表達式。 判斷請求Header是否具有給定名稱且值與正則表達式匹配。
- Header=X-Request-Id, \d+

5.基於Host的斷言

# HostRoutePredicateFactory:接收一個參數,主機名模式。判斷請求的Host是否滿足匹配規則。
- Host=**.testhost.org

6.基於Path請求路徑的斷言

# PathRoutePredicateFactory:接收一個參數,判斷請求的URI部分是否滿足路徑規則。
- Path=/foo/{segment}

7.基於Query請求參數的斷言

# QueryRoutePredicateFactory :接收兩個參數,請求param和正則表達式, 判斷請求參數是否具有給定名稱且值與正則表達式匹配。
- Query=baz, ba.

8.使用

接下來我們驗證幾個內置斷言的使用:

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 路由數組[路由 就是指定當請求滿足什麼條件的時候轉到哪個微服務]
        - id: user-service-route # 當前路由的標識, 要求唯一
          uri: lb://user-service # 請求要轉發到的地址
          predicates: # 斷言(就是路由轉發要滿足的條件)
            - Path=/user/** # 當請求路徑滿足Path指定的規則時,才進行路由轉發
            - Before=2019-11-28T00:00:00.000+08:00 # 限制請求時間在2019-11-28之前
            - Method=POST # 限制請求方式為POST

 

四、過濾器

Gateway也包含過濾器功能,網關服務的過濾器會對請求或響應進行攔截,完成一些通用操作。

1.過濾器執行時機

Gateway的過濾器中有2個執行時機:

  • PRE: 這種過濾器在請求被路由之前調用,可利用這種過濾器實現身份驗證、在集群中選擇請求的微服務、記錄調試信息等

  • POST:這種過濾器在路由到微服務以後執行,可用來為響應添加標準的HTTP Header、收集統計信息和指標、將響應從微服務發送給客戶端等

 

2.過濾器類型

Gateway的Filter從作用範圍可分為2種

  • GatewayFilter:應用到單個路由或者一個分組的路由上

  • GlobalFilter:應用到所有的路由上

 

3.內置局部過濾器

局部過濾器是針對單個路由的過濾器。在SpringCloud Gateway中內置了很多不同類型的網關路由過濾器。具體如下:

過濾器工廠作用參數
AddRequestHeader 為原始請求添加Header Header的名稱及值
AddRequestParameter 為原始請求添加請求參數 參數名稱及值
AddResponseHeader 為原始響應添加Header Header的名稱及值
DedupeResponseHeader 剔除響應頭中重覆的值 需要去重的Header名稱及去重策略
Hystrix 為路由引入Hystrix的斷路器保護 HystrixCommand的名稱
FallbackHeaders 為fallbackUri的請求頭中添加具體的異常信息 Header的名稱
PrefixPath 為原始請求路徑添加首碼 首碼路徑
PreserveHostHeader 為請求添加一個preserveHostHeader=true的屬性,路由過濾器會檢查該屬性以決定是否要發送原始的Host
RequestRateLimiter 用於對請求限流,限流演算法為令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo 將原始請求重定向到指定的URL http狀態碼及重定向的url
RemoveHopByHopHeadersFilter 為原始請求刪除IETF組織規定的一系列Header 預設就會啟用,可以通過配置指定僅刪除哪些Header
RemoveRequestHeader 為原始請求刪除某個Header Header名稱
RemoveResponseHeader 為原始響應刪除某個Header Header名稱
RewritePath 重寫原始的請求路徑 原始路徑正則表達式以及重寫後路徑的正則表達式
RewriteResponseHeader 重寫原始響應中的某個Header Header名稱,值的正則表達式,重寫後的值
SaveSession 在轉發請求之前,強制執行WebSession::save操作
secureHeaders 為原始響應添加一系列起安全作用的響應頭 無,支持修改這些安全響應頭的值
SetPath 修改原始的請求路徑 修改後的路徑
SetResponseHeader 修改原始響應中某個Header的值 Header名稱,修改後的值
SetStatus 修改原始響應的狀態碼 HTTP 狀態碼,可以是數字,也可以是字元串
StripPrefix 用於截斷原始請求的路徑 使用數字表示要截斷的路徑的數量
Retry 針對不同的響應進行重試 retries、statuses、methods、series
RequestSize 設置允許接收最大請求包的大小。如果請求包大小超過設置的值,則返回 413 Payload Too Large 請求包大小,單位為位元組,預設值為5M
ModifyRequestBody 在轉發請求之前修改原始請求體內容 修改後的請求體內容
ModifyResponseBody 修改原始響應體的內容 修改後的響應體內容

 

4.內置局部過濾器的使用

我們只需要把過濾器配置在微服務的配置文件中即可生效;

server:
  port: 7000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos地址
    gateway:
      routes: # 路由數組[路由 就是指定當請求滿足什麼條件的時候轉到哪個微服務]
        - id: user-service-route # 當前路由的標識, 要求唯一
          uri: lb://user-service # 請求要轉發到的地址
          predicates: # 斷言(就是路由轉發要滿足的條件)
            - Path=/user/** # 當請求路徑滿足Path指定的規則時,才進行路由轉發
          filters:
            - SetStatus=2000 # 修改返回狀態

 

5.內置全局過濾器

全局過濾器作用於所有路由無需配置。通過全局過濾器可以實現對許可權的統一校驗,安全性驗證等功能。

SpringCloud Gateway內部也是通過一系列的內置全局過濾器對整個路由轉發進行處理如下:

 

6.自定義全局過濾器(重點)

內置的過濾器已經可以完成大部分的功能,但是對於企業開發的一些業務功能處理,還是需要我們自己編寫過濾器來實現的。

下麵,我們一起通過代碼的形式自定義一個過濾器,去完成統一的許可權校驗。

開發中的鑒權邏輯:

  • 當客戶端第一次請求服務時,服務端對用戶進行信息認證(登錄)

  • 認證通過,將用戶信息進行加密形成token,返回給客戶端,作為登錄憑證

  • 以後每次請求,客戶端都攜帶認證的token

  • 服務端對token進行解密,判斷是否有效。

 下麵的我們自定義一個GlobalFilter,去校驗所有請求的請求參數中是否包含“token”,如何不包含請求參數“token”則不轉發路由,否則執行正常的邏輯。

package com.zhanggen.gateway.auth;

import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

//全局認證過濾器
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    //認證邏輯
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //請求參數數,獲取一個叫token的參數的值  String token =  request.getParamter("token")
        String token = exchange.getRequest().getQueryParams().getFirst("token");

        //判斷是否請求參數中攜帶了token
        if (StringUtils.isBlank(token)) {
            System.out.println("鑒權失敗");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//設置響應碼 resp.setStatus(401)
            return exchange.getResponse().setComplete();//返迴響應
        }

        //調用chain.filter繼續向下游執行
        return chain.filter(exchange);
    }

    //決定當前過濾器的執行級別, 數組越小,優先順序越高
    @Override
    public int getOrder() {
        return 0;
    }
}
com.zhanggen.gateway.auth.AuthGlobalFilter

 當過濾器的order值一樣時,局部過濾器 優先順序高於 全局過濾器;

 

參考


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 【layui2.6.8】有多個文件上傳的組件需要根據後臺數據在頁面載入時動態渲染在一個彈框裡面。彈窗從table表格數據的【編輯】按鈕打開,根據點擊行展示不同的文件,對文件進行查詢、刪除、下載等管理。問題:選擇文件,不上傳,關閉彈窗再打開,剛選的文件雖然不見了,但依然能上傳那個文件,需要打開彈窗時清 ...
  • 📰前言 這個小項目源於github項目:✨50 projects 50 days, 這個項目包含了50個小型前端項目,適合學習了Html+Css+JavaScript但是還沒有學習框架的前端新手作為練習。 這裡是原項目對模糊載入的代碼實現👉Blurry Loading. 📋分析 變化過程: 數 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 對vue項目來說,組件是構成項目的基本單元,為了方便理解,這裡定義兩類組件:頁面組件,功能組件。為什麼需要劃分這兩類組件是從組件復用來考慮的。 我們知道在複雜應用中,頁面狀態管理早已不是早期的簡單的子父組件的傳值,兄弟組件傳值。而當我們尋 ...
  • 自此整個項目前後臺,全部搭建完畢。 今天是最後一天,內容很多,而且也比較常用,一個圖標類數據可視化,一個後臺的許可權管理,都是很經典的類型。 一.數據可視化 1.簡介 專門的一門學科,有專門研究這個的崗位,將數據以各種圖形進行展示 Echarts只能2D,three.js可開發3D 2.canvas繪 ...
  • 什麼是單文件組件? 簡言之,單文件組件就是一個文件擴展名為.vue的single-file-components(SFC)。是Vue.js自定義的一種文件格式,一個.vue文件,就是一個單獨的組件,在文件內封裝了組件的相關代碼:HTML,CSS,JS。 瀏覽器本身並不支持.vue文件,所以必須對.v ...
  • 巨集任務和微任務的隊列入門知識,可以參考之前的文章: JavaScript的事件迴圈機制 巨集任務和微任務在前端面試中,被經常提及到,包括口頭和筆試題 async && await概念 async 使用async關鍵字聲明的函數,是AsyncFunction構造函數的實例,在async函數體內,可以使用 ...
  • 簡介 WebSocket 是雙工的,他支持在客戶端和伺服器之間互相發送文本或二進位消息流,除此功能以外,它還提供了更為複雜的附加擴展: 連接協商和同源策略實施 與現有HTTP基礎設施的互相操作性 面向消息的通信和高效的消息框架 這一點與Socket不同,Socket算是面向位元組,他沒有消息頭、消息尾 ...
  • hi,我是桑小榆,坐在電腦桌旁肝了幾小時的linux服務實現負載均衡等等,乘著還有點時間把消息中間件的內容整理了下,比如現有ActiveMQ、RabbitMQ、RocketMQ、Kafka等常見的消息中間件的各有千秋,以及運用較多的RabbitMQ為例出現的高頻知識內容。 公司生產環境用的是什麼消息 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...