golang基于net/context的链式处理器包装中间件插件库chain的使用
Golang基于net/context的链式处理器包装中间件插件库chain的使用
chain是一个帮助构建嵌套http.Handler实例的Golang包。
安装
go get github.com/codemodus/chain
使用
基本用法
type Chain
func New(handlers ...func(http.Handler) http.Handler) *Chain
func (c *Chain) Append(handlers ...func(http.Handler) http.Handler) *Chain
func (c *Chain) Copy(chain *Chain)
func (c *Chain) End(handler http.Handler) http.Handler
func (c *Chain) EndFn(handlerFunc http.HandlerFunc) http.Handler
func (c *Chain) Merge(chains ...*Chain) *Chain
示例代码
import (
// ...
"github.com/codemodus/chain"
)
func main() {
// ...
// 嵌套处理器会在调用ServeHTTP()前后向响应体写入"0"或"1"
// endHandler会向响应体写入"_END_"
ch00 := chain.New(nestedHandler0, nestedHandler0)
ch001 := ch00.Append(nestedHandler1)
ch1 := chain.New(nestedHandler1)
ch1001 := ch1.Merge(ch001)
mux := http.NewServeMux()
mux.Handle("/00_End", ch00.EndFn(endHandler)) // 响应体: "00_END_00"
mux.Handle("/001_End", ch001.EndFn(endHandler)) // 响应体: "001_END_100"
mux.Handle("/1001_End", ch1001.EndFn(endHandler)) // 响应体: "1001_END_1001"
// ...
}
可嵌套的http.Handler
func nestableHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ...
next.ServeHTTP(w, r)
// ...
})
}
Go 1.7+/chain 2.0+的变化
从Go 1.7开始,http包的Request类型包含一个字段(通过Context()方法访问),该字段持有context.Context的实现。此外,context包已被添加到标准库中。现在不再需要之前版本的chain中定义的自定义Handler。
性能基准
这些结果是比较正常嵌套函数和链式函数的性能。每个基准测试在最终处理程序之前包含10个函数。
go1.7
benchmark iter time/iter bytes alloc allocs
--------- ---- --------- ----------- ------
BenchmarkChain10 20000 61.01 μs/op 3684 B/op 51 allocs/op
BenchmarkChain10-4 20000 68.62 μs/op 3691 B/op 51 allocs/op
BenchmarkChain10-8 20000 69.33 μs/op 3696 B/op 51 allocs/op
BenchmarkNest10 20000 60.36 μs/op 3684 B/op 51 allocs/op
BenchmarkNest10-4 20000 70.82 μs/op 3692 B/op 51 allocs/op
BenchmarkNest10-8 20000 71.03 μs/op 3697 B/op 51 allocs/op
更多关于golang基于net/context的链式处理器包装中间件插件库chain的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang基于net/context的链式处理器包装中间件插件库chain的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 基于 net/context 的链式处理器中间件库 chain 使用指南
在 Go 语言中,构建中间件链是 Web 开发中常见的模式。下面我将介绍如何使用 net/context
构建链式处理器中间件,并提供一个简单但功能完整的实现。
基本概念
链式中间件允许你将多个处理器函数串联起来,按顺序执行,每个中间件可以在请求处理前后执行特定逻辑。
核心实现
package chain
import (
"context"
"net/http"
)
// Handler 是一个函数类型,接收 context 并返回错误
type Handler func(context.Context) error
// Middleware 是中间件类型,接收一个 Handler 并返回一个新的 Handler
type Middleware func(Handler) Handler
// Chain 结构体包含中间件列表
type Chain struct {
middlewares []Middleware
}
// New 创建一个新的中间件链
func New(middlewares ...Middleware) Chain {
return Chain{middlewares: append(([]Middleware)(nil), middlewares...)}
}
// Then 将中间件应用到最终的处理器
func (c Chain) Then(h Handler) Handler {
for i := range c.middlewares {
h = c.middlewares[len(c.middlewares)-1-i](h)
}
return h
}
// Append 向链中添加新的中间件
func (c Chain) Append(middlewares ...Middleware) Chain {
newMiddlewares := make([]Middleware, 0, len(c.middlewares)+len(middlewares))
newMiddlewares = append(newMiddlewares, c.middlewares...)
newMiddlewares = append(newMiddlewares, middlewares...)
return Chain{middlewares: newMiddlewares}
}
// HTTPHandler 将 Handler 转换为 http.Handler
func HTTPHandler(h Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if err := h(ctx); err != nil {
// 处理错误
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}
使用示例
下面展示如何使用这个链式中间件库:
package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
)
func main() {
// 创建中间件链
chain := New(
loggingMiddleware,
timeoutMiddleware(2 * time.Second),
authMiddleware,
)
// 创建最终处理器
handler := chain.Then(func(ctx context.Context) error {
// 业务逻辑
fmt.Println("处理请求...")
time.Sleep(1 * time.Second) // 模拟处理时间
return nil
})
// 转换为 http.Handler 并启动服务
http.Handle("/", HTTPHandler(handler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
// 日志中间件
func loggingMiddleware(next Handler) Handler {
return func(ctx context.Context) error {
start := time.Now()
fmt.Printf("开始处理请求 at %v\n", start)
err := next(ctx)
fmt.Printf("请求处理完成, 耗时: %v\n", time.Since(start))
return err
}
}
// 超时中间件
func timeoutMiddleware(timeout time.Duration) Middleware {
return func(next Handler) Handler {
return func(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
return next(ctx)
}
}
}
// 认证中间件
func authMiddleware(next Handler) Handler {
return func(ctx context.Context) error {
// 这里可以检查认证信息
fmt.Println("检查认证...")
return next(ctx)
}
}
高级用法
1. 条件中间件
func conditionalMiddleware(condition bool, mw Middleware) Middleware {
if condition {
return mw
}
return func(next Handler) Handler {
return next
}
}
// 使用示例
chain := New(
conditionalMiddleware(config.EnableLogging, loggingMiddleware),
// 其他中间件...
)
2. 错误处理中间件
func errorHandlingMiddleware(next Handler) Handler {
return func(ctx context.Context) error {
err := next(ctx)
if err != nil {
// 记录错误或执行其他处理
fmt.Printf("发生错误: %v\n", err)
}
return err
}
}
3. 上下文值传递
func requestIDMiddleware(next Handler) Handler {
return func(ctx context.Context) error {
reqID := "req-" + uuid.New().String()
ctx = context.WithValue(ctx, "requestID", reqID)
return next(ctx)
}
}
// 在处理器中获取
func businessHandler(ctx context.Context) error {
reqID := ctx.Value("requestID").(string)
fmt.Println("Request ID:", reqID)
// 业务逻辑...
return nil
}
总结
这个链式中间件库提供了以下优势:
- 灵活性:可以自由组合中间件
- 可读性:清晰的链式调用结构
- 可扩展性:易于添加新的中间件
- context 集成:充分利用 Go 的 context 包
你可以根据项目需求扩展这个基础实现,添加更多功能如性能监控、请求验证等中间件。