goweb中间件

中间件基本概念

中间件(Middleware)是一种在HTTP请求到达最终处理程序(Handler)之前或之后执行特定功能的机制。

在 Go 语言里,net/http 是标准库中用于构建 HTTP 服务器的包,中间件则是处理 HTTP 请求时常用的技术。中间件其实就是一个函数,它会接收一个 http.Handler 类型的参数,并且返回另一个 http.Handler。中间件能够在请求到达最终处理程序之前或者响应返回客户端之前执行一些通用操作,像日志记录、认证、压缩等。

下面是一个简单的中间件函数示例:

go 复制代码
go
package main

import (
    "log"
    "net/http"
)

// 中间件函数,接收一个 http.Handler 并返回另一个 http.Handler
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 在请求处理之前执行的操作
        log.Printf("Received request: %s %s", r.Method, r.URL.Path)

        // 调用下一个处理程序
        next.ServeHTTP(w, r)

        // 在请求处理之后执行的操作
        log.Printf("Request completed: %s %s", r.Method, r.URL.Path)
    })
}

// 最终处理程序
func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, World!"))
}

func main() {
    // 创建一个新的 mux
    mux := http.NewServeMux()

    // 应用中间件到最终处理程序
    mux.Handle("/", loggingMiddleware(http.HandlerFunc(helloHandler)))

    // 启动服务器
    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}
  • 中间件函数 loggingMiddleware:
  • 它接收一个 http.Handler 类型的参数 next,代表下一个要执行的处理程序。
  • 返回一个新的 http.HandlerFunc,在这个函数里可以执行请求处理前后的操作。
  • next.ServeHTTP(w, r) 这行代码会调用下一个处理程序。
  • 最终处理程序 helloHandler:

helloHandler是实际处理请求的函数,它会向客户端返回 "Hello, World!"。

中间件链式调用

多个中间件可以串联起来形成处理链:

go 复制代码
package main

import (
    "log"
    "net/http"
)

// 日志中间件
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Received request: %s %s", r.Method, r.URL.Path)
        next.ServeHTTP(w, r)
        log.Printf("Request completed: %s %s", r.Method, r.URL.Path)
    })
}

// 认证中间件
func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 简单的认证逻辑
        authHeader := r.Header.Get("Authorization")
        if authHeader != "Bearer secret_token" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

// 最终处理程序
func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello, World!"))
}

func main() {
    mux := http.NewServeMux()

    // 应用多个中间件到最终处理程序
    finalHandler := loggingMiddleware(authMiddleware(http.HandlerFunc(helloHandler)))
    mux.Handle("/", finalHandler)

    log.Println("Server started on :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}
  • 这里新增了一个 authMiddleware 中间件,用于简单的认证。
  • 在 main 函数里,先把 authMiddleware 应用到 helloHandler 上,再把 loggingMiddleware 应用到结果上,这样就实现了多个中间件的组合。

通过使用中间件,能够让代码更具模块化和可维护性,并且可以在多个处理程序之间共享通用的逻辑。

中间件链中传递自定义参数

​场景​ ​:需要在多个中间件间共享数据(如请求ID、用户会话)

​实现方式​ ​:通过 context.Context 传递参数

go 复制代码
package main

import (
	"context"
	"fmt"
	"net/http"
)

// 中间件函数
func middleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 设置上下文值
		ctx := context.WithValue(r.Context(), "key", "value")
		ctx = context.WithValue(ctx, "user_id", 123)
		r = r.WithContext(ctx)

		// 调用下一个处理函数
		next.ServeHTTP(w, r)
	})
}

// 处理函数
func handler(w http.ResponseWriter, r *http.Request) {
	// 从上下文中获取值
	value := r.Context().Value("key").(string)
	userID := r.Context().Value("user_id").(int)
	fmt.Fprintf(w, "Received user_id %d value: %v", userID, value)
}

func main() {
	// 创建一个处理函数
	mux := http.NewServeMux()
	mux.HandleFunc("/", handler)

	http.Handle("/", middleware(mux))

	// 启动服务器
	fmt.Println("Server started on :80")
	http.ListenAndServe(":80", nil)
}

​特点​​:

  • 数据在中间件链中透明传递
  • 避免全局变量和参数层层传递

相关推荐
ldmd2844 小时前
地图生成算法(噪声篇-Perlin,Simplex,Value noise)
算法·go·地图生成
妙码生花5 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(四十一):增加管理员账号管理接口
后端·go·gin
名字还没想好☜2 天前
Go for-range 循环变量陷阱:goroutine 里全打印同一个值(Go 1.22 前后差异)
开发语言·后端·golang·go
光头闪亮亮2 天前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(中)
android·c++·go
光头闪亮亮2 天前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(上)
android·sqlite·go
光头闪亮亮2 天前
Fyne ( go跨平台GUI )项目实战-项目开发必备基础知识(下)
android·c++·go
妙码生花2 天前
从 PHP 到 AI + Golang,程序员自救转型手记(三十六):多驱动上传接口
后端·go·ai编程
golang学习记3 天前
从 CRUD 到生产就绪:Go 后端必须掌握的五个分布式系统模式
go
名字还没想好☜3 天前
Go 结构体内存对齐:调整字段顺序,同样的字段省下 40% 内存
开发语言·后端·golang·go·内存对齐