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)
}

​特点​​:

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

相关推荐
百锦再13 小时前
第15章 并发编程
android·java·开发语言·python·rust·django·go
虫洞没有虫19 小时前
Go语言学习笔记(一)
笔记·go·区块链
wohuidaquan1 天前
AI为何跳过你?GEO中的E-E-A-T权重
go
百锦再1 天前
选择Rust的理由:从内存管理到抛弃抽象
android·java·开发语言·后端·python·rust·go
百锦再2 天前
大话Rust的前生今世
开发语言·后端·rust·go·内存·时间·抽象
俞凡4 天前
Golang 构建网络漏洞扫描器
go
百锦再4 天前
第14章 智能指针
android·java·开发语言·git·rust·go·错误
Mgx4 天前
用 Go 写个“端口扫描器”,100 行代码扫描你家路由器?(别慌,只是看看谁在开门!)
go
mao毛4 天前
go项目适配DTM,gozero已经适配dtm了,goframe项目要怎么适配?
微服务·go
Mgx4 天前
一文讲透 Go 的 defer:你的“善后管家“,别让他变成“背锅侠“!
go