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.rhkb.cn/news/42833.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【随手记】支持多模态输入的 AI Chatbot App

一、Streamlit 1、Streamlit开发文档 官方文档&#xff1a;https://docs.streamlit.io/ 中文文档&#xff1a;https://blog.csdn.net/weixin_44458771/article/details/135495928 2、Streamlit命令行启动 pip install streamlit streamlit run app.py --server.port 85013…

为什么大模型在 OCR 任务上表现不佳?

编者按&#xff1a; 你是否曾经用最先进的大语言模型处理企业文档&#xff0c;却发现它把财务报表中的“$1,234.56”读成了“123456”&#xff1f;或者在处理医疗记录时&#xff0c;将“0.5mg”误读为“5mg”&#xff1f;对于依赖数据准确性的运营和采购团队来说&#xff0c;这…

关于ArcGIS中加载影像数据,符号系统中渲染参数的解析

今天遇到一个很有意思的问题&#xff0c;故记录下来&#xff0c;以作参考和后续的研究。欢迎随时沟通交流。如果表达错误或误导&#xff0c;请各位指正。 正文 当我们拿到一幅成果影像数据的时候&#xff0c;在不同的GIS软件中会有不同效果呈现&#xff0c;但这其实是影像是…

智能舵机:AI融合下的自动化新纪元

在自动化的浪潮中&#xff0c;智能舵机以其独特的魅力和卓越的性能&#xff0c;正引领着自动化产业迈向新的高度。今天&#xff0c;让我们一起走进智能舵机的世界&#xff0c;感受AI技术为其带来的无限可能。 一、智能舵机&#xff1a;自适应控制的先锋 智能舵机&#xff0c;…

计算机二级WPS Office第四套电子表格

解题过程 排名的函数有三个&#xff1a;rank函数、rank.avg函数、rank.eq函数

【数学建模】(启发式算法)蚁群算法(Ant Colony Optimization)的详解与应用

蚁群算法(Ant Colony Optimization)详解与应用 文章目录 蚁群算法(Ant Colony Optimization)详解与应用前言1. 蚁群算法的生物学基础2. 蚁群算法的基本原理2.1 算法框架2.2 状态转移规则2.3 信息素更新规则 3. 蚁群算法的实现4. 蚁群算法的改进4.1 MAX-MIN蚁群系统(MMAS)4.2 精…

基于Springboot的网上订餐系统 【源码】+【PPT】+【开题报告】+【论文】

网上订餐系统是一个基于Java语言和Spring Boot框架开发的Web应用&#xff0c;旨在为用户和管理员提供一个便捷的订餐平台。该系统通过简化餐饮订购和管理流程&#xff0c;为用户提供快速、高效的在线订餐体验&#xff0c;同时也为管理员提供完善的后台管理功能&#xff0c;帮助…

使用idea开发spark程序

新建scala 项目 创建lib目录 将spark jars/ 路径下所有jar 复制到 lib目录 添加依赖 创建scala 程序 package sparkimport org.apache.spark.{SparkConf, SparkContext}object WordCount {def main(args: Array[String]): Unit {val conf new SparkConf().setAppName(&q…

CORDIC算法:三角函数的硬件加速革命——从数学原理到FPGA实现的超高效计算方案

计算机该如何求解三角函数&#xff1f;或许你的第一印象是采用泰勒展开&#xff0c;或者采用多项式进行逼近。对于前者&#xff0c;来回的迭代计算开销成本很大&#xff1b;对于后者&#xff0c;多项式式逼近在较窄的范围內比较接近&#xff0c;超过一定范围后&#xff0c;就变…

无需docker三步安装deepseek可视化操作软件-Open-WebUI

在以前安装Open-WebUI时&#xff0c;需要通过docker安装, 针对小白来讲呢有些麻烦, 因此这里推荐使用python环境安装Open-WebUI,简单快捷上手快! 1. Mac安装python3.11 以上的环境, windows同学直接官网下载安装包msi,双击安装即可1.1 Mac直接安装 python3.11brew install pyt…

3DGS较真系列

目录 引言 三维高斯飞溅(3DGS) 总体流程 SFM算法 1.特征提取&#xff1a; 2.特征匹配&#xff1a; 3.图像对优选&#xff1a; 4.相机位姿估计及空间点坐标获取&#xff1a; 5.三角化确立新图像地图点&#xff1a; 6.重建场景及其约束&#xff1a; 3DGS 1.捏雪球 2…

【计网】网络、互连网、互联网的认识和区分

一、些杂乱的知识点&#xff1a; 1.Internet是由数量极大的各种计算机网络连接起来的。 2.世界上最大的计算机网络Internet叫互联网&#xff08;互联网 &#xff01; 互连网&#xff09;。 3.互联网的两个基本特点&#xff1a; &#xff08;1&#xff09;互通性&#xff1a…

手机零售行业的 AI 破局与创新降本实践 | OceanBase DB大咖说

OceanBase《DB 大咖说》第 20 期&#xff0c;我们邀请了九机与九讯云的技术总负责人&#xff0c;李远军&#xff0c;为我们分享手机零售企业如何借力分布式数据库OceanBase&#xff0c;赋能 AI 场景&#xff0c;并通过简化架构实现成本管控上的突破与创新。 李远军于2016年加入…

高并发金融系统,“可观测-可追溯-可回滚“的闭环审计体系

一句话总结 在高并发金融系统中&#xff0c;审计方案设计需平衡"观测粒度"与"系统损耗"&#xff0c;通过双AOP实现非侵入式采集&#xff0c;三表机制保障操作原子性&#xff0c;最终形成"可观测-可追溯-可回滚"的闭环体系。 业务痛点与需求 在…

迅为iTOP-RK3576人工智能开发板Android 系统接口功能测试

2.1 开机启动 开发板接通电源&#xff0c;并按下电源开关&#xff0c;系统即启动&#xff0c;在启动过程中&#xff0c;系统会显示下图中的开机画面&#xff0c;它们分别是 Android 系统启动时的 Logo 画面&#xff1a; 最后会显示如下解锁画面&#xff1a; 2.2 命令终端 将…

Linux云计算SRE-第二十一周

构建单节点prometheus&#xff0c;部署node exporter和mongo exporter。构建kibana大盘。包含主机PU使用率&#xff0c;主机MEM使用率&#xff0c;主机网络包速度。mongo db大盘&#xff0c;包含节点在线状态&#xff0c;读操作延迟等 一、实验环境准备 - 节点信息&#xff1…

蓝桥杯 - 简单 - 产品360度展示

介绍 在电子商务网站中&#xff0c;用户可以通过鼠标或手势交互实现 360 度全方位查看产品&#xff0c;提升用户体验。现在需要你设计一个 Pipeline 管道函数&#xff0c;用于控制 360 度展示产品的动画序列&#xff0c;通过管道连接各个动画步骤&#xff0c;使产品以流畅的方…

【Rust基础】使用LanceDB构建高性能以图搜图服务

简介 最近使用LanceDB构建了一个以图搜图服务&#xff0c;用于相似图片检索&#xff0c;支持以下功能&#xff1a; 搜索 支持向量搜索&#xff0c;查找相似图片支持通过item_id搜索精确搜索 数据管理 支持添加数据、批量导入CSV或JSON数据支持已有数据修改、删除 API 提供HTT…

蓝桥杯备考:模拟算法之排队接水

简单的模拟就行了&#xff0c;把他们的时间排序&#xff0c;时间最少的先上&#xff0c;然后算出每个人的等待时间的平均值 #include <iostream> #include <algorithm> using namespace std; const int N 1e310; int n; double sum; double ret; struct node{int…

zynq7000 + ucos3 + lwip202_v1_2调试过程

1 现在裸机应用上验证lwip 跑起来可能会报错&#xff0c;看下面的链接解决 zynq 网卡Phy setup error问题 zynq 网卡Phy setup error问题-CSDN博客 2 ping同以后&#xff0c;在zynq上添加ucos系统 链接如下&#xff1a; ZYNQ移植uCOSIII_zynq ucos-CSDN博客 3 移植lwip协议…