golang基于httprouter的依赖注入中间件路由插件库nchi的使用

Golang基于httprouter的依赖注入中间件路由插件库nchi的使用

nchi简介

nchi是一个轻量级、优雅且快速的路由库,用于构建Go HTTP服务。它特别适合编写大型REST API服务,随着项目增长和变化仍能保持可维护性。nchi基于以下两个库构建:

  • nject依赖注入框架
  • 最快的Go http路由器httprouter

安装

go get github.com/muir/nchi

简单示例

package main

import (
	"net/http"

	"github.com/muir/nchi"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := nchi.NewRouter()
	r.Use(middleware.Logger) // 使用日志中间件
	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("welcome")) // 根路由处理
	})
	http.ListenAndServe(":3000", r) // 启动服务器
}

REST API完整示例

package main

import (
	//...
	"github.com/muir/nchi"
	"github.com/muir/nvelope"
	"github.com/muir/nject/v2"
	"github.com/go-chi/chi/v5/middleware"
)

func main() {
	r := nchi.NewRouter()

	// 基础中间件栈
	r.Use(
		middleware.RequestID,  // 请求ID
		middleware.RealIP,     // 真实IP
		middleware.Logger,     // 日志
		nchi.DecodeJSON,       // JSON解码
	)

	// 错误处理中间件
	r.Use(func(inner func() error, w http.ResponseWriter) {
		err := inner()
		if err == nil { 
			return
		}
		code := nvelope.GetReturnCode(err)
		w.WriteHeader(code)
		w.Write([]byte(err.Error()))
	})

	// 设置请求超时
	r.Use(middleware.Timeout(60 * time.Second))

	// 简单路由
	r.Get("/", func(w http.ResponseWriter) {
		w.Write([]byte("hi"))
	})

	// 文章资源路由
	r.Route("/articles", func(r nchi.Router) {
		r.With(paginate).Get("/", listArticles)                        // GET /articles
		r.With(paginate).Get("/:month/:day/:year", listArticlesByDate) // GET /articles/01-16-2017

		r.Post("/", createArticle)                                     // POST /articles
		r.Get("/search", searchArticles)                               // GET /articles/search

		r.Get("/:articleSlug", getArticleBySlug)                       // GET /articles/home-is-toronto

		// 子路由
		r.Route("/:articleID", func(r nchi.Router) {
			r.Use(LoadArticle) // 加载文章中间件
			r.Get("/", getArticle)          // GET /articles/123
			r.Put("/", updateArticle)       // PUT /articles/123
			r.Delete("/", deleteArticle)    // DELETE /articles/123
		})
	})

	// 挂载管理子路由
	r.Mount("/admin", adminRouter())

	http.ListenAndServe(":3333", r)
}

// 加载文章依赖注入函数
func LoadArticle(params nchi.Params) (*Article, nject.TerminalError) {
	articleID := params.ByName("articleID")
	article, err := dbGetArticle(articleID)
	if errors.Is(err, sql.NotFound) {
		return nil, nvelope.NotFound(err)
	}
	return article, err
}

// 获取文章处理函数
func getArticle(article *Article, w http.ResponseWriter) {
	w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
}

中间件支持

nchi支持两种形式的中间件:

  1. 标准中间件:

    • func(http.HandlerFunc) http.HandlerFunc
    • func(http.Handler) http.Handler
  2. 依赖注入中间件

nchi会自动检测标准中间件并将其转换为nject框架可用的形式。

开发状态

nchi目前运行良好,没有太多变化。如果您有任何改进建议,请提交问题。


更多关于golang基于httprouter的依赖注入中间件路由插件库nchi的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于httprouter的依赖注入中间件路由插件库nchi的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang基于httprouter的依赖注入中间件路由插件库nchi使用指南

nchi是一个基于httprouter构建的轻量级路由库,它提供了依赖注入和中间件支持,非常适合构建RESTful API服务。下面我将详细介绍nchi的使用方法。

安装nchi

go get github.com/muir/nchi

基本使用

package main

import (
	"fmt"
	"net/http"
	
	"github.com/muir/nchi"
)

func main() {
	router := nchi.NewRouter()
	
	router.Get("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Hello, World!")
	})
	
	http.ListenAndServe(":8080", router)
}

中间件支持

nchi支持中间件链式调用:

func logger(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Printf("Request: %s %s\n", r.Method, r.URL.Path)
		next.ServeHTTP(w, r)
	})
}

func auth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		token := r.Header.Get("Authorization")
		if token != "secret" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}

func main() {
	router := nchi.NewRouter()
	
	// 全局中间件
	router.Use(logger)
	
	// 路由组中间件
	api := router.Group("/api")
	api.Use(auth)
	
	api.Get("/users", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "User list")
	})
	
	http.ListenAndServe(":8080", router)
}

依赖注入

nchi支持依赖注入,可以将服务注入到处理器中:

type UserService struct {
	// 模拟用户服务
}

func (s *UserService) GetUsers() []string {
	return []string{"Alice", "Bob", "Charlie"}
}

func main() {
	userService := &UserService{}
	
	router := nchi.NewRouter()
	
	// 注入服务到处理器
	router.Get("/users", func(w http.ResponseWriter, r *http.Request, s *UserService) {
		users := s.GetUsers()
		fmt.Fprintf(w, "Users: %v", users)
	}).Inject(userService)
	
	http.ListenAndServe(":8080", router)
}

路由参数

nchi继承了httprouter的路由参数特性:

func main() {
	router := nchi.NewRouter()
	
	router.Get("/users/:id", func(w http.ResponseWriter, r *http.Request) {
		id := nchi.URLParam(r, "id")
		fmt.Fprintf(w, "User ID: %s", id)
	})
	
	http.ListenAndServe(":8080", router)
}

错误处理

可以自定义错误处理器:

func main() {
	router := nchi.NewRouter()
	
	// 自定义404处理器
	router.NotFound = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, "Custom 404 page")
	})
	
	// 自定义方法不允许处理器
	router.MethodNotAllowed = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprint(w, "Method not allowed")
	})
	
	http.ListenAndServe(":8080", router)
}

完整示例

package main

import (
	"fmt"
	"log"
	"net/http"
	
	"github.com/muir/nchi"
)

type Database struct {
	// 模拟数据库
}

func (db *Database) GetUserName(id string) string {
	// 模拟数据库查询
	return "User_" + id
}

func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("X-API-Key") != "secret" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}

func main() {
	db := &Database{}
	router := nchi.NewRouter()
	
	// 全局中间件
	router.Use(authMiddleware)
	
	// 用户路由组
	userRouter := router.Group("/users")
	{
		userRouter.Get("/:id", func(w http.ResponseWriter, r *http.Request, db *Database) {
			id := nchi.URLParam(r, "id")
			name := db.GetUserName(id)
			fmt.Fprintf(w, "User: %s", name)
		}).Inject(db)
		
		userRouter.Post("/", func(w http.ResponseWriter, r *http.Request) {
			// 创建用户逻辑
			w.WriteHeader(http.StatusCreated)
			fmt.Fprint(w, "User created")
		})
	}
	
	// 健康检查
	router.Get("/health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprint(w, "OK")
	})
	
	log.Println("Server started on :8080")
	log.Fatal(http.ListenAndServe(":8080", router))
}

总结

nchi结合了httprouter的高性能和依赖注入的便利性,主要特点包括:

  1. 基于httprouter,性能优异
  2. 支持中间件链
  3. 依赖注入支持
  4. 简洁的API设计
  5. 支持路由参数和通配符

对于需要构建高性能API且希望简化依赖管理的项目,nchi是一个很好的选择。

回到顶部