49.【.NET8 實戰--孢子記賬--從單體到微服務--轉向微服務】--擴展功能--集成網關--Refit跨服務調用

Refit是一個用于.NET平臺的REST庫,它可以將REST API轉換為實時類型安全的接口。通過Refit,我們可以輕松實現微服務之間的跨服務調用,使服務間通信變得更加簡單和類型安全。本文將介紹如何在我們的項目中使用Refit來實現微服務間的通信。

一、什么是Refit

Refit是一個強大的REST客戶端庫,它能夠將普通的HTTP API接口轉換為類型安全的.NET接口。通過聲明式的接口定義,Refit可以自動處理HTTP請求的序列化和反序列化,使得微服務之間的通信變得更加簡單和可靠。它的工作原理是在運行時動態生成實現類,將接口方法轉換為對應的HTTP請求。

在使用Refit時,我們只需要定義一個包含所需API調用的接口,并使用特性(Attributes)來描述HTTP請求的細節,如URL、請求方法、請求頭等。Refit會自動處理底層的HTTP通信細節,包括請求的構建、發送以及響應的處理,讓開發者可以專注于業務邏輯的實現,而不必關心底層的通信實現細節。

相比傳統的HttpClient方式,Refit提供了更優雅的API調用方式,并且具有強類型檢查的優勢,可以在編譯時發現潛在的問題。此外,Refit還支持多種高級特性,如請求重試、超時控制、自定義序列化等,使其成為.NET微服務架構中不可或缺的工具之一。

1.1 Refit的主要特性

Refit作為一個強大的REST客戶端庫,提供了豐富的特性支持。它通過簡單的C#接口聲明方式來定義API調用,支持包括GET、POST、PUT、DELETE在內的各種HTTP方法,并可以通過特性靈活配置請求參數和請求頭。在類型安全方面,Refit提供了編譯時類型檢查機制,使用強類型的請求和響應模型,有效避免了運行時可能出現的類型錯誤。對于數據處理,Refit支持JSON、XML等多種格式的自動序列化和反序列化,可以自定義序列化器,并能自動處理復雜對象的轉換。在配置選項方面,Refit支持請求重試策略、超時時間設置、自定義消息處理器,以及集成認證和授權功能。性能方面,Refit通過高效的HTTP請求處理、請求緩存支持和連接池管理來確保最佳性能。

1.2 使用場景

Refit在多個場景中展現出其強大的實用價值。在微服務架構中,它能夠有效處理服務發現和注冊、負載均衡以及斷路器模式等微服務間的通信需求。對于外部API集成,Refit可以優雅地封裝第三方服務調用、RESTful API,并作為高效的WebAPI客戶端。在分布式系統中,Refit支持服務編排、數據聚合,并能夠處理跨服務事務,使得分布式系統的開發和維護變得更加簡單和可靠。

二、SP.FinanceService服務使用Refit

我們將以SP.FinanceService服務為例,介紹如何使用Refit實現跨服務調用,其中包括了Refit接口定義、調用Refit接口、Refit接口與目標微服務的綁定。

2.1 Refit 接口

在這個服務中,修改和新增記賬記錄的時候需要調用SP.ConfigService服務的/api/configs/by-type接口獲取用戶配置的默認幣種。先來看一下這個接口,代碼如下:

///<summary>
/// 根據配置類型獲取配置
///</summary>
[HttpGet("by-type/{type}")]
public ActionResult<ConfigResponse> QueryByType([FromRoute] ConfigTypeEnum type)
{// more code ...
}

這個接口接受一個路由參數type,這個參數用來區分獲取的配置類型,并返回ConfigResponse類型的參數。type參數是一個枚舉類型ConfigTypeEnum,用于標識不同的配置類型,比如默認幣種、默認賬本等。接口通過[FromRoute]特性將參數綁定到路由中,這意味著參數值將從URL路徑中獲取,而不是查詢字符串或請求體。返回的ConfigResponse對象包含了配置的具體信息。

我們已經了解了這個接口,下一步我們就要使用Refit在SP.FinanceService服務中調用它。首先,新建RefitClient文件夾,并在里面新建Refit客戶端接口IConfigServiceApi,我們不需要實現它,這是因為Refit已經為我們提供了默認的實現,這個默認實現已經滿足了大部分的情況。代碼如下:

using Refit;
using SP.Common.Model.Enumeration;
using SP.FinanceService.Models.Response;namespace SP.FinanceService.RefitClient;/// <summary>
/// 配置服務接口
/// </summary>
public interface IConfigServiceApi
{/// <summary>/// 根據類型獲取配置/// </summary>/// <param name="type"></param>/// <returns></returns>[Get("/api/configs/by-type/{type}")]Task<ApiResponse<ConfigResponse>> QueryByType(ConfigTypeEnum type);
}

接口上的[Get("/api/configs/by-type/{type}")]特性是Refit提供的HTTP方法特性之一,它聲明了這個接口方法將通過HTTP GET請求來調用遠程服務。特性中的路徑"/api/configs/by-type/{type}"定義了實際的API端點,其中{type}是一個路由參數占位符,會在運行時被實際的參數值替換。當我們調用這個接口方法時,Refit會首先通過服務發現機制獲取目標服務的可用實例地址。然后,它會將獲取到的服務基地址與接口路徑組合,構建完整的請求URL。Refit會自動處理參數的序列化,將方法參數正確地映射到HTTP請求中,最后發送HTTP請求到目標服務。

Tip:在使用Refit定義接口時,一定要將接口定義為異步的,這是因為Refit調用數據跨服務調用,異步操作允許系統同時處理多個請求,而不是串行處理。其次,也會避免同步調用可能在高并發情況下出現的死鎖問題。再者,在等待網絡響應時,線程可以執行其他任務,提高CPU和內存的利用效率。

2.2 調用Refit接口

在編寫完成Refit接口,我們就要開始調用它了,調用的方式和調用本地方法一樣,先來看一下代碼:

// more code ../// <summary>
/// 記賬服務實現類
/// </summary>
public class AccountingServerImpl : IAccountingServer
{// more code ...///<summary>/// 用戶配置接口///</summary>private readonly IConfigServiceApi _configService;/// <summary>/// 記賬服務構造函數/// </summary>/// <param name="dbContext"></param>/// <param name="autoMapper"></param>/// <param name="configService"></param>/// <param name="accountBookServer"></param>/// <param name="rabbitMqMessage"></param>/// <param name="currencyServer"></param>public AccountingServerImpl(FinanceServiceDbContext dbContext, IMapper autoMapper,IConfigServiceApi configService, IAccountBookServer accountBookServer, RabbitMqMessage rabbitMqMessage,ICurrencyService currencyServer){_dbContext = dbContext;_autoMapper = autoMapper;_accountBookServer = accountBookServer;_rabbitMqMessage = rabbitMqMessage;_currencyServer = currencyServer;_configService = configService;}// more code .../// <summary>/// 從用戶配置中獲取用戶設置的目標幣種/// </summary>/// <returns>返回目標幣種ID</returns>private long GetUserTargetCurrencyId(){ApiResponse<ConfigResponse> apiResponse = _configService.QueryByType(ConfigTypeEnum.Currency).Result;// 檢查響應是否成功,并且內容不為空if (apiResponse.IsSuccessStatusCode && apiResponse.Content != null){return long.Parse(apiResponse.Content.Value ?? string.Empty);}throw new RefitException($"獲取匯率失敗: {apiResponse.StatusCode}");}
}

在上面的代碼中,我們實現了對SP.ConfigService服務的調用,就像調用本地方法一樣簡單直觀。具體來說,我們在AccountingServerImpl類的構造函數中注入了IConfigServiceApi接口,這個接口是我們之前定義的Refit客戶端接口。在GetUserTargetCurrencyId方法中,我們通過_configService.QueryByType(ConfigTypeEnum.Currency)調用遠程服務的API,獲取用戶配置的默認幣種。這個調用過程中,Refit會自動處理HTTP請求的構建和發送,并將返回的結果封裝在ApiResponse<ConfigResponse>對象中。通過檢查響應的狀態碼和內容,我們可以確保調用成功并獲取到所需的配置值。如果調用失敗或返回內容為空,則拋出RefitException異常。

我們看到QueryByType方法封裝了ConfigResponse,這個類型定義在了當前服務中。我們為什么要在當前服務中重復定義ConfigResponse,而不是將配置服務的ConfigResponse提取為公共類型呢?這是因為服務的調用方不一定需要全部的屬性,而且這樣做可以降低服務之間的耦合度。在微服務架構中,每個服務應該是獨立的,能夠獨立部署和演進。如果我們將響應類型放在公共庫中,那么當配置服務的響應結構發生變化時,所有依賴這個公共類型的服務都需要更新和重新部署。通過在每個服務中定義自己需要的響應類型,我們可以更好地控制服務之間的依賴關系,實現服務的松耦合。另外,這種方式也允許不同的服務根據自己的需求定義不同的響應結構,提供了更大的靈活性。當然這也意味著我們需要在服務之間進行適當的數據映射,但這種額外的工作是值得的,因為它帶來了更好的服務獨立性和可維護性。

2.3 Refit接口與目標微服務綁定

最后一步,我們需要將編寫的Refit接口與目標微服務進行綁定,這是實現跨服務調用的關鍵環節。通過綁定告訴Refit應該在Nacos中查找哪個具體的服務實例。這個綁定過程通常在服務啟動時的依賴注入配置中完成。綁定完成后,當我們通過Refit接口發起調用時,框架會自動從Nacos獲取目標服務的可用實例列表,然后根據配置的負載均衡策略選擇合適的實例進行調用。在Program中新增代碼如下:


// more code ...// 注冊 Refit 客戶端(基于通用服務發現 + Nacos,無需硬編碼 BaseUrl)
var nacosSection = builder.Configuration.GetSection("nacos");
var groupName = nacosSection.GetValue<string>("GroupName") ?? "DEFAULT_GROUP";
var clusterName = nacosSection.GetValue<string>("ClusterName") ?? "DEFAULT";builder.Services.AddNacosRefitClient<IConfigServiceApi>(serviceName: "SPConfigService",groupName: groupName,clusterName: clusterName,scheme: "http");// more code ...

在上面的代碼中,我們通過AddNacosRefitClient擴展方法將Refit客戶端接口與Nacos服務發現進行了集成。這個方法需要幾個關鍵參數:serviceName指定了要調用的目標服務在Nacos中注冊的名稱,在這里是"SPConfigService";groupNameclusterName分別從配置文件中獲取服務組名和集群名,如果配置文件中沒有指定這些值,則使用默認值"DEFAULT_GROUP"和"DEFAULT";scheme參數指定了服務調用使用的協議,這里使用"http"。通過這種配置,當服務啟動時,框架會自動在Nacos中查找名為"SPConfigService"的服務實例,并在運行時根據服務發現的結果動態構建請求URL。這種方式避免了硬編碼服務地址,使得服務調用更加靈活和可維護。當目標服務的實例發生變化時,Nacos會自動更新可用實例列表,確保服務調用始終能夠找到正確的目標實例。

Tip:在這里,我們將服務間的調用配置為了http,這是因為服務間的內部調用基本上是安全的。在微服務架構中,服務通常部署在同一個內部網絡或VPC(Virtual Private Cloud)中,網絡環境是受控和隔離的。使用http而不是https可以減少TLS/SSL加密解密帶來的性能開銷,同時簡化了證書管理的復雜性。但是,如果服務需要跨越不同的網絡環境或需要更高的安全要求,我們也可以將scheme配置為https,并配置相應的證書來確保通信安全。在生產環境中,具體使用http還是https應該根據實際的安全需求和部署環境來決定。

三、總結

本文詳細介紹了在.NET微服務架構中使用Refit實現跨服務調用的方法。通過Refit這個強大的REST客戶端庫,我們可以將HTTP API轉換為類型安全的.NET接口,大大簡化了服務間通信的實現。文章以SP.FinanceService服務為例,展示了如何定義Refit接口、實現跨服務調用以及將接口與目標微服務進行綁定。通過與Nacos服務發現的集成,實現了服務地址的動態發現和負載均衡,避免了硬編碼服務地址的問題。這種實現方式不僅提供了類型安全的服務調用,還保持了服務間的松耦合,使得微服務架構更加靈活和可維護。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94917.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94917.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94917.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

日志ELK、ELFK、EFK

一.ELK架構Elasticsearch Logstash Kibana 數據庫日志處理日志顯示1.logstash的使用&#xff08;1&#xff09;input&#xff1a;輸入&#xff08;2&#xff09;filter&#xff1a;處理&#xff08;3&#xff09;output&#xff1a;輸出2.ELFK架構Filebeat-->Elasticsearc…

【CUDA進階】MMA分析Bank Conflict與Swizzle(下)

目錄前言1. bank conflict 分析2. 通過 padding 解決 bank conflict3. mma 搭配 wmma 實現矩陣乘法計算3.1 代碼實現3.2 補充&#xff1a;stmatrix_sync 函數分析3.3 補充&#xff1a;__shfl_sync 函數詳解4. swizzle 原理講解5. swizzle 實現思路講解結語下載鏈接參考前言 學習…

天氣查詢系統

項目要求 項目知識點 問題與解決 代碼分部 結果展示 項目要求 1.顯示天氣預報系統界面 2.系統可以通過選擇城市配置獲取不同城市天氣信息 3.查看實時的天氣信息 &#xff08;當前溫度、最高溫度、最低溫度、當前濕度、最高濕度、最低濕度、風向、風力、風級等信息&#x…

三重積分的對稱性

文章目錄前言柱面球面前言 規律作息 柱面 太牛了。我完全看不懂。實際上就類似于極坐標系。 球面 看到這么多東西&#xff0c;我真害怕。今天是 8.30 &#xff0c;不管 9.10 有沒有復習完概率的強化&#xff0c;我都一定要開始套卷&#xff0c;還有專業課的復習。?\phi?…

深入理解 RabbitMQ:從底層原理到實戰落地的全維度指南

引言&#xff1a; 本文總字數&#xff1a;約 18500 字預計閱讀時間&#xff1a;45 分鐘 為什么我們需要 RabbitMQ&#xff1f; 在當今分布式系統架構中&#xff0c;消息隊列已成為不可或缺的核心組件。想象一下&#xff0c;當你在電商平臺下單時&#xff0c;系統需要處理庫存…

寬帶有丟包,重傳高的情況怎么優化

寬帶丟包和重傳率高是一個非常影響網絡體驗的常見問題。它會導致游戲卡頓、視頻通話模糊、網頁加載慢等。別擔心&#xff0c;我們可以按照從易到難的順序&#xff0c;系統地排查和優化。請遵循以下步驟&#xff1a;第一步&#xff1a;基礎排查&#xff08;自己動手&#xff0c;…

Kotlin 協程之Channel 的高階應用

前言 了解了 Channel 的基礎概念和基本使用 后&#xff0c;我們再來看一看 Channel 的特性以及高階應用。 Channel 是"熱流" 熱流概念 Channel 是熱流&#xff08;Hot Stream&#xff09;&#xff0c;具備以下特性&#xff1a; 數據的生產和消費是兩套獨立的流程 …

PostgreSQL表空間(Tablespace)作用(管理數據庫對象的存儲位置)(pg_default、pg_global)

文章目錄**1. 靈活的數據存儲管理**- **邏輯與物理分離**&#xff1a;表空間為數據庫對象&#xff08;如表、索引&#xff09;提供了一個邏輯名稱與物理存儲路徑的映射。用戶無需直接操作底層文件路徑&#xff0c;只需通過表空間名稱管理數據。- **多數據庫共享表空間**&#x…

Ansible 核心運維場景落地:YUM 倉庫、SSH 公鑰、固定 IP 配置技巧

1&#xff1a;如何一次性驗證所有主機能否被 Ansible 訪問&#xff1f; 答&#xff1a;使用臨時命令&#xff1a;ansible all -m ansible.builtin.ping或驗證 sudo 是否正常&#xff1a;ansible all -m ansible.builtin.ping --become -K2&#xff1a;如何用 Ansible 統一配置…

rman導致的報錯ORA-27037: unable to obtain file status

有套3節點的11204集群環境&#xff0c;在db2上配置了rman備份&#xff0c;今天例行檢查時發現db1和db3上不定期有報錯&#xff0c;報錯如下&#xff1a;Control file backup creation failed:failure to open backup target file /u01/app/oracle/product/11.2.0/db_1/dbs/snap…

Kubernetes 與 GitOps 的深度融合實踐指南

前言&#xff1a;在云原生技術飛速發展的今天&#xff0c;Kubernetes&#xff08;簡稱 K8s&#xff09;已成為容器編排領域的事實標準&#xff0c;而 GitOps 作為一種基于 Git 的云原生運維理念&#xff0c;正與 K8s 深度融合&#xff0c;為企業實現自動化、可追溯、可審計的應…

REST-assured 接口測試編寫指南

REST-assured 簡介 REST-assured 是一個基于 Java 的 DSL&#xff08;領域特定語言&#xff09;庫&#xff0c;專門用于簡化 RESTful API 測試的編寫。它提供了流暢的 API 接口&#xff0c;使得測試代碼更加易讀易寫&#xff0c;支持 JSON 和 XML 等多種響應格式的驗證。 基本環…

內網應用如何實現外網訪問?外地通過公網地址訪問內網服務器的設置方法

一、內網應用程序在外網需要連接訪問遇到的問題我們經常需要在內網中部署服務&#xff0c;比如一個 Web 服務器或者數據庫&#xff0c;但由于本地沒有公網IP&#xff0c;這些服務無法直接從外地公網訪問。如自己家里的監控系統&#xff0c;在家時能查看&#xff0c;但出門在外就…

ubuntu24.04 QT中配置opencv4.12

假如生成的opencv路徑是&#xff1a;/usr/local/opencv4.12QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c17# You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINE…

客戶端是否都需要主動發送`FindService`報文來尋找服務

<摘要> 在AUTOSAR SOME/IP-SD的服務發現流程中&#xff0c;客戶端是否需要主動發送FindService報文來尋找服務&#xff0c;是理解服務訂閱邏輯的一個關鍵。這將直接影響到事件組訂閱的觸發時機和網絡行為。下文將結合規范&#xff0c;對這一問題進行深入剖析。 <解析&…

Go語言流式輸出實戰:構建高性能實時應用

什么是流式輸出&#xff1f; 流式輸出&#xff08;Streaming Output&#xff09;是一種服務器推送技術&#xff0c;允許數據在生成過程中逐步發送到客戶端&#xff0c;而不是等待所有數據準備就緒后一次性發送。這種技術顯著改善了用戶體驗&#xff0c;特別是在處理大量數據或長…

操作系統上的Docker安裝指南:解鎖容器化新世界

摘要&#xff1a;本文詳細介紹了Docker在不同操作系統上的安裝方法。主要內容包括&#xff1a;Windows系統通過Docker Desktop安裝&#xff0c;需啟用Hyper-V和WSL2&#xff1b;Mac系統同樣使用Docker Desktop&#xff0c;根據芯片類型選擇版本&#xff1b;Linux系統以Ubuntu為…

【微信小程序】分別解決H5的跨域代理問題 和小程序正常不需要代理問題

——總問&#xff1a;何為跨域和代理&#xff1f; &#x1f539;什么叫跨域&#xff1f; 前端在瀏覽器里發請求時&#xff0c;如果 域名 / 協議 / 端口 三個中有一個不一樣&#xff0c;就會觸發 跨域問題。 例子&#xff1a; 頁面跑在 http://localhost:5173你要請求接口 http:…

數字簽名 digital signature

文章目錄1、嚴謹的定義2、技術原理&#xff1a;如何工作&#xff1f;第一步&#xff1a;發送者 - 簽名過程第二步&#xff1a;接收者 - 簽名驗證過程3、C語言實現示例4、關鍵技術要點5、安全注意事項6、最重要的應用&#xff1a;TLS/SSL 與網站安全1、嚴謹的定義 數字簽名是一…

對于STM32工程模板

工程模板文件下載鏈接 https://download.csdn.net/download/qq_58631644/91809234 重命名 打開這個文件夾 重命名保持一致 雙擊打開