Golang中間件的原理與實現

一. 什么是 Middleware?

中間件(Middleware) 是一種 高階函數,它接受一個函數作為輸入,并返回一個經過增強的函數。它的核心思想是通過函數的遞歸嵌套,動態地為函數添加功能。在 Golang 中,中間件的常見應用場景包括日志記錄、權限驗證、異常處理、格式化輸入輸出等。在 python 中叫裝飾器

// Middleware 是一個高階函數,接收一個處理函數 Handler,返回一個經過加工的處理函數 Handler
type Middleware func(Handler) Handler

二. 為什么使用 Middleware ?

在開發中,你可能遇到這樣的需求:

  • 日志記錄:在函數執行前后記錄日志,包括輸入參數、執行時間等

  • 權限驗證:根據用戶權限決定是否允許執行請求

  • 錯誤處理:捕獲函數執行過程中的錯誤并進行集中處理

假設沒有中間件,這段代碼可能會變得非常繁瑣:

func (s *SomeService) ExampleHandler(ctx context.Context, data string) {Log(ctx) // 日志操作if err := Auth(ctx); err != nil { // 檢查權限return err}return s.ProcessBusiness(ctx, data) // 核心業務邏輯
}

這種寫法使得業務邏輯與額外的附加操作交織在一起,不易維護

通過中間件,我們能夠將這些邏輯解耦,使得代碼既簡潔又清晰:

func (s *SomeService) ExampleHandler(ctx context.Context, data string) {return s.ProcessBusiness(ctx, data) // 專注于業務處理
}

通過中中間件件的功能插入,業務代碼的關注點單一,增強了代碼的可讀性和可維護性。

三. 中間件調用過程原理

我們大致分為 3 步來講解其過程

  1. 實現 Middleware

  2. 實現 業務處理函數 Handler

  3. 嵌套 Middlreware , 并包裹 Handler

3.1 實現 Middleware

根據第一章中間件的抽象定義,實現 2 個特化的 中間件

// 抽象中間件
type Middleware func(Handler) Handler// 日志中間件 的實現
func LogMiddleware(next Handler) Handler {return func(data string) string {fmt.Println("--- LogMiddleware: Log Before: ", time.Now())result := next(data) // 調用下一個處理函數(被捕獲的 next)fmt.Println("--- LogMiddleware: Log After: ", time.Now())return result}
}// 鑒權中間件 的實現
func AuthMiddleware(next Handler) Handler {return func(data string) string {fmt.Println("	--- AuthMiddleware: Authing ---")if data == "壞人" {return "Access Denied"}result := next(data)fmt.Println("	--- AuthMiddleware: Authing ---")return result}
}

3.2 實現 Handler

// 業務處理函數
func BusinessHandler(data string) string {fmt.Println("		--- 業務 <<" + data + ">> 處理成功")return data
}

3.3 嵌套 Middlreware , 包裹 Handler

在實際開發中,我們往往需要多個中間件共同作用,比如既要記錄日志又要驗證權限。這種情況下,需要將多個中間件有序地組合起來。

組合的方式是通過 鏈式調用(Chain),如下代碼展示了如何實現一個 Chain 函數:

func Chain(middlewares ...Middleware) Middleware {return func(handler Handler) Handler {// 從后向前, 挨個嵌套中間件for i := len(middlewares) - 1; i >= 0; i-- {handler = middlewares[i](handler)}return handler}
}
// 1. 嵌套 Middleware
combinedMiddleware := Chain(LogMiddleware, AuthMiddleware)
// 2. 包裹 Handler
finalHandler := combinedMiddleware(BusinessHandler)

Middleware 的運行過程可以比喻為 “流水線加工”:原始數據經過中間件逐層處理,最終返回加工完成的結果

--- LogMiddleware: Log Before:  2025-03-28 18:21:04.315295 +0800 CST m=+0.000067959--- AuthMiddleware: Authing ------ 業務 <<創建文件>> 處理成功--- AuthMiddleware: Authing ---
--- LogMiddleware: Log After:  2025-03-28 18:21:04.315417 +0800 CST m=+0.000190084

完整代碼

要完整展示前述代碼的調用流程,可以參考如下完整例子:

package mainimport ("fmt""time"
)// Middleware: 是一個高階函數, 接收一個處理函數,輸出一個處理后的處理函數
type Middleware func(Handler) Handler// 日志中間件 的實現
func LogMiddleware(next Handler) Handler {return func(data string) string {fmt.Println("--- LogMiddleware: Log Before: ", time.Now())result := next(data) // 調用下一個處理函數(被捕獲的 next)fmt.Println("--- LogMiddleware: Log After: ", time.Now())return result}
}// 鑒權中間件 的實現
func AuthMiddleware(next Handler) Handler {return func(data string) string {fmt.Println("	--- AuthMiddleware: Authing ---")if data == "壞人" {return "Access Denied"}result := next(data)fmt.Println("	--- AuthMiddleware: Authing ---")return result}
}// 輸入:n個中間件(高階函數)
// 輸出:1個中間件(高階函數)
// 函數:將n個中間件層層嵌套,1個高階函數包一個高階函數
// 意義:這意味著,你傳入一個Handler函數,其將會經歷Middleware函數的層層處理
func Chain(middlewares ...Middleware) Middleware {return func(handler Handler) Handler {// 從后向前, 挨個嵌套中間件for i := len(middlewares) - 1; i >= 0; i-- {handler = middlewares[i](handler)}return handler}
}// ---------------------- Handler --------------------------
// 請求最終的處理函數(在網絡中對應的是 http 請求的業務邏輯處理)
type Handler func(data string) string// 業務處理函數
func BusinessHandler(data string) string {fmt.Println("		--- 業務 <<" + data + ">> 處理成功")return data
}// 使用示例
func main() {combinedMiddleware := Chain(LogMiddleware, AuthMiddleware)finalHandler := combinedMiddleware(BusinessHandler)finalHandler("創建文件")
}

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

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

相關文章

算法設計學習3

實驗目的及要求&#xff1a; 1.加強對結構體的應用。 2.熟悉字符計數排序。 實驗設備環境&#xff1a; 1.微型計算機 2.DEV C(或其他編譯軟件) 實驗步驟&#xff1a; 任務&#xff1a;要求使用自定義函數來實現 輸入一段文本&#xff0c;統計每個字符出現的次數&#xff0c;按…

Vue2和3的vue-router:生命周期、懶加載

Vue2 vue-router 在 Vue 2 中使用 vue-router 可以方便地管理單頁面應用&#xff08;SPA&#xff09;中的路由。理解 vue-router 的生命周期和懶加載機制對于構建高效的 Vue 應用至關重要。以下是一些關鍵點和示例代碼來幫助你理解這些概念。 Vue Router 的生命周期 vue-rou…

【408--考研復習筆記】計算機網絡----知識點速覽

目錄 一、計算機網絡體系結構 1.計算機網絡的定義與功能&#xff1a; 2.網絡體系結構相關概念&#xff1a; 3.OSI 七層模型與 TCP/IP 模型&#xff1a; 4.通信方式與交換技術&#xff1a; 電路交換 報文交換 分組交換 5.端到端通信和點到點通信&#xff1a; 6.計算機…

MySQL-- 多表查詢的分類,SQL92與SQL99,7種JOIN的實現,SQL99語法的新特性

目錄 一&#xff0c;多表查詢的分類 角度1&#xff1a;等值連接 vs 非等值連接 角度2&#xff1a;自連接 vs 非自連接 角度3&#xff1a;內連接 vs 外連接 二&#xff0c;SQL92語法實現內連接&#xff1a;見上&#xff0c;略SQL92語法實現外連接&#xff1a;使用 -…

時間輪算法:原理、演進與應用實踐指南

目錄 1. 時間輪算法基礎 1.1 什么是時間輪算法&#xff1f; 1.2 核心組成部分 2. 基本時間輪的實現機制 2.1 時間輪的構成要素 2.2 工作原理詳解 3. 基本時間輪的局限性 3.1 時間范圍限制問題 3.2 簡單解決方案及其缺陷 4. 時間輪算法的演進 4.1 Round機制&#xff…

Unity 常見報錯 定位和查找方法

1.控制臺 直接看報錯信息 2.打log 例子&#xff1a; for(int i 0;i < 8;i) {Debug.Log(i);//這是打的log,看看到底i是幾的時候出問題gameObject.name strs[i];} 3.斷點調試 &#xff08;1&#xff09;在你想打斷點的行&#xff0c;左邊空白處點擊可以打斷點&#xff…

第十八章:Python實戰專題:北京市水資源數據可視化與圖書館書籍管理應用開發

今天我要和大家分享兩個非常有趣的Python實戰項目&#xff1a;一個是北京市2001-2017年水資源數據的可視化分析&#xff0c;另一個是圖書館書籍管理應用程序的開發。這兩個項目都使用了Python的主流庫&#xff0c;比如Pandas、Matplotlib和Tkinter&#xff0c;非常適合初學者學…

音視頻基礎(音視頻的錄制和播放原理)

文章目錄 一、錄制原理**1. 音視頻數據解析****2. 音頻處理流程****3. 視頻處理流程****4. 同步控制****5. 關鍵技術點****總結** 二、播放原理**1. 音視頻數據解析****2. 音頻處理流程****3. 視頻處理流程****4. 同步控制****5. 關鍵技術點****總結** 一、錄制原理 這張圖展示…

Nginx多域名HTTPS配置全攻略:從證書生成到客戶端安裝

一、業務背景 在現代Web開發中&#xff0c;HTTPS已成為保障數據傳輸安全的標準協議。特別是對于地圖類API服務&#xff08;如高德地圖&#xff09;&#xff0c;往往需要同時支持多個子域名&#xff08;如webapi.amap.com、restapi.amap.com等&#xff09;的HTTPS訪問。傳統方式…

Redis原理:rename命令

RENAME key newkey 將一個key重命名為新key&#xff0c;如果key不存在&#xff0c;則會返回異常。如果newKey已經存在&#xff0c;則會被覆蓋&#xff0c;其實newKey會被顯示的刪除&#xff0c;所以如果newKey是一個大key&#xff0c;則會引起延遲。 源碼 void renameCommand…

k8s污點與容忍

k8s污點與容忍 k8s污點管理常用命令effect標記值查看污點添加污點刪除污點 node污點與容忍污點容忍yaml示例容忍放大基于污點的驅逐驅逐時排除指定服務 設置master調度設置master盡量不調度允許master節點調度pod恢復Master Only狀態將node標記為不可調度狀態(節點警戒)設置nod…

(BFS)題解:P9425 [藍橋杯 2023 國 B] AB 路線

題解&#xff1a;P9425 [藍橋杯 2023 國 B] AB 路線 題目傳送門 P9425 [藍橋杯 2023 國 B] AB 路線 一、題目描述 給定一個NM的迷宮&#xff0c;每個格子標記為A或B。從左上角(1,1)出發&#xff0c;需要移動到右下角(N,M)。移動規則是&#xff1a;必須交替走K個A格子和K個B…

python-leetcode 62.搜索插入位置

題目&#xff1a; 給定一個排序數組和一個目標值&#xff0c;在數組中找到目標值&#xff0c;并返回其索引。如果目標值不存在于數組中&#xff0c;返回它將會被按順序插入的位置 方法一&#xff1a;二分查找 假設題意是在排序數組中尋找是否存在一個目標值&#xff0c;則可以…

【計網速通】計算機網絡核心知識點和高頻考點——數據鏈路層(一)

數據鏈路層核心知識點&#xff08;一&#xff09; 一、數據鏈路層概述 1.1 基本概念 數據鏈路層位于OSI模型的第二層&#xff0c;介于物理層和網絡層之間&#xff0c;主要負責在相鄰節點之間傳輸和識別數據幀。 1.2 主要功能 幀同步&#xff1a;識別幀的開始和結束差錯控制…

模型部署與調用

目錄 部署 ollama下載 模型版本選擇 ?編輯 對照表 控制臺執行 調用 部署 大模型部署我使用的是Ollama&#xff0c;點擊跳轉 接下來我將在本地使用ollama就行模型部署的演示 ollama下載 模型版本選擇 對照表 大家可以根據自己的顯卡配置選擇對應的模型版本 控制臺執…

Rstudio如何使用Conda環境配置的R

前言 Rstudio作為一款流行的R語言集成開發環境&#xff08;IDE&#xff09;&#xff0c;為用戶提供了便捷的編程體驗。然而&#xff0c;不同項目可能需要不同版本的R&#xff0c;這就需要我們靈活切換R版本。除了在之前文章中提到的使用 Docker 部署不同版本的 R 的方法之外&am…

C++---RAII模式

一、RAII模式概述 1. 定義 RAII&#xff08;Resource Acquisition Is Initialization&#xff09;即資源獲取即初始化&#xff0c;是C中用于管理資源生命周期的一種重要編程模式。其核心在于將資源的獲取和釋放操作與對象的生命周期緊密綁定。當對象被創建時&#xff0c;資源…

【功能開發】DSP F2837x 檢測中斷所有函數運行一次的時間

要查看 DSP F28377 的 CPU 在 50 微秒一次的中斷內所有程序運行完總共占用了中斷多長時間&#xff0c;可以采用硬件定時器測量和軟件計時兩種常見方法。 方法一&#xff1a;使用硬件定時器測量 原理 利用 DSP 內部的高精度硬件定時器&#xff0c;在中斷開始時記錄定時器的值…

MAC環境給docker換源

2025-03-28 MAC環境給docker換源 在官網下載docker ,dmg 文件 參考&#xff1a; https://blog.csdn.net/qq_73162098/article/details/145014490 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},&q…

Vulnhub-zico2靶機打靶記錄

本篇文章旨在為網絡安全滲透測試靶機教學。通過閱讀本文&#xff0c;讀者將能夠對滲透Vulnhub系列zico2靶機有一定的了解 一、信息收集階段 靶機下載地址&#xff1a;https://download.vulnhub.com/zico/zico2.ova 因為靶機為本地部署虛擬機網段&#xff0c;查看dhcp地址池設…