微服務之服務網關

来源: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
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...