golang HTTP处理器链式包装插件库catena的使用

golang HTTP处理器链式包装插件库catena的使用

简介

catena是一个用于gRPC拦截器链式包装的Go语言库,它可以帮助开发者更方便地管理和组合多个gRPC拦截器。

安装

使用以下命令安装catena库:

go get -u github.com/codemodus/catena

使用示例

下面是一个完整的示例,展示如何使用catena创建和管理gRPC拦截器链:

package main

import (
	"context"
	"log"
	"net"

	"github.com/codemodus/catena"
	"google.golang.org/grpc"
)

// 示例gRPC服务
type server struct{}

// 示例gRPC方法
func (s *server) SayHello(ctx context.Context, req *HelloRequest) (*HelloReply, error) {
	return &HelloReply{Message: "Hello " + req.Name}, nil
}

// 第一个拦截器
func interceptor1(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
	log.Println("Interceptor 1 - before handler")
	resp, err = handler(ctx, req)
	log.Println("Interceptor 1 - after handler")
	return resp, err
}

// 第二个拦截器
func interceptor2(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
	log.Println("Interceptor 2 - before handler")
	resp, err = handler(ctx, req)
	log.Println("Interceptor 2 - after handler")
	return resp, err
}

func main() {
	// 创建拦截器链
	chain := catena.NewUnaryServerCatena(interceptor1, interceptor2)
	
	// 可以继续添加更多拦截器
	chain.Append(
		func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
			log.Println("Interceptor 3 - before handler")
			resp, err = handler(ctx, req)
			log.Println("Interceptor 3 - after handler")
			return resp, err
		},
	)
	
	// 创建gRPC服务器并应用拦截器链
	s := grpc.NewServer(chain.ServerOption())
	
	// 注册服务
	RegisterGreeterServer(s, &server{})
	
	// 启动服务器
	lis, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

主要功能

catena提供了以下主要功能:

type UnaryServerCatena
    // 创建新的拦截器链
    func NewUnaryServerCatena(is ...grpc.UnaryServerInterceptor) *UnaryServerCatena
    
    // 向链中添加更多拦截器
    func (c *UnaryServerCatena) Append(is ...grpc.UnaryServerInterceptor) *UnaryServerCatena
    
    // 复制拦截器链
    func (c *UnaryServerCatena) Copy(catena *UnaryServerCatena)
    
    // 获取组合后的拦截器
    func (c *UnaryServerCatena) Interceptor() grpc.UnaryServerInterceptor
    
    // 合并多个拦截器链
    func (c *UnaryServerCatena) Merge(cs ...*UnaryServerCatena) *UnaryServerCatena
    
    // 获取gRPC服务器选项
    func (c *UnaryServerCatena) ServerOption() grpc.ServerOption

更多信息

catena库主要用于简化gRPC拦截器的管理和组合,特别适合需要多个拦截器协同工作的场景。通过链式调用,可以更清晰地组织和维护拦截器逻辑。


更多关于golang HTTP处理器链式包装插件库catena的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang HTTP处理器链式包装插件库catena的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Catena - Golang HTTP处理器链式包装插件库

Catena是一个轻量级的Go语言HTTP处理器链式包装库,它允许你以优雅的方式组合多个中间件和处理函数。下面我将详细介绍如何使用Catena。

安装

go get github.com/go-catena/catena

基本用法

package main

import (
	"net/http"
	
	"github.com/go-catena/catena"
)

func main() {
	// 创建一个新的Catena链
	chain := catena.New()
	
	// 添加中间件和处理函数
	chain.Use(loggerMiddleware)
	chain.Use(authMiddleware)
	chain.Handle("/", homeHandler)
	
	// 启动HTTP服务器
	http.ListenAndServe(":8080", chain)
}

func loggerMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 记录请求信息
		log.Printf("%s %s", r.Method, r.URL.Path)
		// 调用下一个处理器
		next.ServeHTTP(w, r)
	})
}

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 简单的认证检查
		if r.Header.Get("Authorization") != "valid-token" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Welcome to the home page!"))
}

高级特性

1. 分组路由

func main() {
	chain := catena.New()
	
	// 公共路由组
	public := chain.Group()
	public.Use(loggerMiddleware)
	public.Handle("/", homeHandler)
	
	// 私有路由组
	private := chain.Group()
	private.Use(authMiddleware)
	private.Handle("/dashboard", dashboardHandler)
	
	http.ListenAndServe(":8080", chain)
}

2. 条件中间件

func main() {
	chain := catena.New()
	
	// 只在特定路径上应用中间件
	chain.UseIf(loggerMiddleware, func(r *http.Request) bool {
		return r.URL.Path != "/health"
	})
	
	chain.Handle("/health", healthHandler)
	chain.Handle("/", homeHandler)
	
	http.ListenAndServe(":8080", chain)
}

3. 错误处理

func main() {
	chain := catena.New()
	
	// 添加错误处理中间件
	chain.Use(errorHandlerMiddleware)
	
	chain.Handle("/", func(w http.ResponseWriter, r *http.Request) {
		// 模拟错误
		panic("something went wrong")
	})
	
	http.ListenAndServe(":8080", chain)
}

func errorHandlerMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				// 处理panic
				w.WriteHeader(http.StatusInternalServerError)
				fmt.Fprintf(w, "Error: %v", err)
			}
		}()
		next.ServeHTTP(w, r)
	})
}

4. 自定义配置

func main() {
	// 创建带有自定义配置的Catena实例
	chain := catena.NewWithConfig(catena.Config{
		Recover:       true,  // 自动恢复panic
		LogRequests:   true,  // 记录请求日志
		LogRecoveries: true,  // 记录恢复的panic
	})
	
	chain.Handle("/", homeHandler)
	
	http.ListenAndServe(":8080", chain)
}

最佳实践

  1. 中间件顺序:将全局中间件(如日志、恢复)放在前面,特定中间件(如认证)放在后面。

  2. 错误处理:使用专门的错误处理中间件捕获和处理错误。

  3. 性能考虑:避免在中间件中进行昂贵的操作,如频繁的数据库查询。

  4. 测试:为每个中间件编写单元测试,确保它们按预期工作。

// 测试示例
func TestAuthMiddleware(t *testing.T) {
	req := httptest.NewRequest("GET", "/", nil)
	rec := httptest.NewRecorder()
	
	// 测试未授权请求
	handler := authMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		t.Error("Should not reach here")
	}))
	handler.ServeHTTP(rec, req)
	
	if rec.Code != http.StatusUnauthorized {
		t.Errorf("Expected status %d, got %d", http.StatusUnauthorized, rec.Code)
	}
	
	// 测试授权请求
	req.Header.Set("Authorization", "valid-token")
	rec = httptest.NewRecorder()
	handler.ServeHTTP(rec, req)
	
	if rec.Code != http.StatusOK {
		t.Errorf("Expected status %d, got %d", http.StatusOK, rec.Code)
	}
}

Catena提供了一种简洁而强大的方式来组织你的HTTP中间件和处理逻辑,使代码更易于维护和扩展。

回到顶部