当前位置: 首页 > article >正文

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 main

import (
	"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.kler.cn/a/613641.html

相关文章:

  • 使用 Selenium 构建简单高效的网页爬虫
  • Docker Compose 基础知识
  • rnn的ho的维度 (num_layers * num_directions, batchsize, hidden_size)
  • 付账问题 | 第9届蓝桥杯省赛C++A组
  • Kafka 偏移量
  • 安卓车载app面经
  • 嵌入式单片机程序的映像文件解读
  • idea中如何使用git
  • git在实践使用中的操作流程
  • Java----用正则表达式爬取数据
  • SpringCloud Hystrix的用法详解
  • 【C#.NET】Web API项目Swagger配置扩展
  • vscode无法打开Terminal终端
  • 电脑连不上手机热点会出现的小bug
  • 博卡软件管理中心8:为美容美发行业量身打造的轻量级管理方案
  • swagger上传图片请求报错
  • 3.27学习总结
  • 介绍几种创意登录页(含完整源码)
  • Uniapp使用大疆SDK打包离线原生插件二
  • 力扣HOT100之普通数组:41. 缺失的第一个正数