golang基于trie树实现的高性能HTTP路由插件库goblin的使用

Golang基于Trie树实现的高性能HTTP路由插件库goblin的使用

goblin是一个基于Trie树实现的Golang HTTP路由器,具有高性能和轻量级的特点。

特性

  • 支持Go 1.16及以上版本
  • 基于Trie树的简单数据结构
  • 轻量级
    • 代码行数:2428
    • 包大小:140K
  • 除了标准包外没有其他依赖
  • 兼容net/http
  • 比net/http的ServeMux更高级
    • 基于方法的路由
    • 命名参数路由
    • 基于正则表达式的路由
    • 中间件支持
    • 可定制的错误处理程序
    • 默认OPTIONS处理程序
  • 0分配
    • 静态路由实现0分配
    • 命名路由约3分配

安装

go get -u github.com/bmf-san/goblin

使用示例

基于方法的路由

r := goblin.NewRouter()

r.Methods(http.MethodGet).Handler(`/`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "/")
}))

r.Methods(http.MethodGet, http.MethodPost).Handler(`/methods`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if r.Method == http.MethodGet {
        fmt.Fprintf(w, "GET")
    }
    if r.Method == http.MethodPost {
        fmt.Fprintf(w, "POST")
    }
}))

http.ListenAndServe(":9999", r)

命名参数路由

r := goblin.NewRouter()

r.Methods(http.MethodGet).Handler(`/foo/:id`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    id := goblin.GetParam(r.Context(), "id")
    fmt.Fprintf(w, "/foo/%v", id)
}))

r.Methods(http.MethodGet).Handler(`/foo/:name`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    name := goblin.GetParam(r.Context(), "name")
    fmt.Fprintf(w, "/foo/%v", name)
}))

http.ListenAndServe(":9999", r)

基于正则表达式的路由

r.Methods(http.MethodGet).Handler(`/foo/:id[^\d+$]`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    id := goblin.GetParam(r.Context(), "id")
    fmt.Fprintf(w, "/foo/%v", id)
}))

中间件

// 实现返回http.Handler的中间件函数
func global(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "global: before\n")
		next.ServeHTTP(w, r)
		fmt.Fprintf(w, "global: after\n")
	})
}

func first(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "first: before\n")
		next.ServeHTTP(w, r)
		fmt.Fprintf(w, "first: after\n")
	})
}

func second(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "second: before\n")
		next.ServeHTTP(w, r)
		fmt.Fprintf(w, "second: after\n")
	})
}

func third(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "third: before\n")
		next.ServeHTTP(w, r)
		fmt.Fprintf(w, "third: after\n")
	})
}

r := goblin.NewRouter()

// 设置全局中间件
r.UseGlobal(global)
r.Methods(http.MethodGet).Handler(`/globalmiddleware`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "/globalmiddleware\n")
}))

// 使用Use方法应用中间件
r.Methods(http.MethodGet).Use(first).Handler(`/middleware`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "middleware\n")
}))

// 可以配置多个中间件
r.Methods(http.MethodGet).Use(second, third).Handler(`/middlewares`, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "middlewares\n")
}))

http.ListenAndServe(":9999", r)

请求/globalmiddleware会得到以下结果:

global: before
/globalmiddleware
global: after

请求/middleware会得到以下结果:

global: before
first: before
middleware
first: after
global: after

请求/middlewares会得到以下结果:

global: before
second: before
third: before
middlewares
third: after
second: after
global: after

自定义错误处理程序

func customMethodNotFound() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "customMethodNotFound")
	})
}

func customMethodAllowed() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "customMethodNotAllowed")
	})
}

r := goblin.NewRouter()
r.NotFoundHandler = customMethodNotFound()
r.MethodNotAllowedHandler = customMethodAllowed()

http.ListenAndServe(":9999", r)

默认OPTIONS处理程序

func DefaultOPTIONSHandler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNoContent)
	})
}

r := goblin.NewRouter()
r.DefaultOPTIONSHandler = DefaultOPTIONSHandler()

http.ListenAndServe(":9999", r)

默认的OPTIONS处理程序在处理CORS OPTIONS请求(预检请求)时非常有用。

设计

goblin内部使用Trie树数据结构,相比基数树(Radix Tree),Trie树虽然性能稍逊,但算法更简单,更易于理解和维护。

路由定义在内部表示为树结构,每个HTTP方法都有自己的树,每个节点包含处理程序和中间件定义等数据。

完整示例

package main

import (
	"fmt"
	"net/http"

	"github.com/bmf-san/goblin"
)

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

	// 简单路由
	r.Methods(http.MethodGet).Handler("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Welcome to goblin!")
	}))

	// 命名参数路由
	r.Methods(http.MethodGet).Handler("/user/:name", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		name := goblin.GetParam(r.Context(), "name")
		fmt.Fprintf(w, "Hello, %s!", name)
	}))

	// 正则表达式路由
	r.Methods(http.MethodGet).Handler("/post/:id[^\\d+$]", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := goblin.GetParam(r.Context(), "id")
		fmt.Fprintf(w, "Post ID: %s", id)
	}))

	// 中间件示例
	authMiddleware := func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Println("Auth middleware - before")
			next.ServeHTTP(w, r)
			fmt.Println("Auth middleware - after")
		})
	}

	r.Methods(http.MethodGet).Use(authMiddleware).Handler("/private", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Private area")
	}))

	fmt.Println("Server started at :8080")
	http.ListenAndServe(":8080", r)
}

goblin是一个简单、高效且功能丰富的HTTP路由器,适合需要高性能路由的各种Golang web应用场景。


更多关于golang基于trie树实现的高性能HTTP路由插件库goblin的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang基于trie树实现的高性能HTTP路由插件库goblin的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Goblin实现高性能HTTP路由

Goblin是一个基于Trie树实现的高性能HTTP路由库,专为Go语言设计。它通过Trie树的数据结构优化了路由匹配性能,特别适合需要处理大量路由规则的场景。

Goblin核心特性

  1. 基于Trie树的路由匹配:高效的路由查找算法
  2. 高性能:比标准库和许多流行路由库更快
  3. 支持参数路由:如/user/:id
  4. 通配符支持:如/static/*filepath
  5. 中间件支持:灵活的中间件机制

基本使用示例

首先安装Goblin:

go get github.com/bmf-san/goblin

1. 基本路由

package main

import (
	"fmt"
	"net/http"
	
	"github.com/bmf-san/goblin"
)

func main() {
	r := goblin.NewRouter()
	
	// 注册路由
	r.Methods(http.MethodGet).Handler("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, Goblin!")
	}))
	
	http.ListenAndServe(":8080", r)
}

2. 参数路由

r.Methods(http.MethodGet).Handler("/user/:id", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	params := goblin.GetParams(r.Context())
	id := params["id"]
	fmt.Fprintf(w, "User ID: %s", id)
}))

3. 通配符路由

r.Methods(http.MethodGet).Handler("/static/*filepath", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	params := goblin.GetParams(r.Context())
	filepath := params["filepath"]
	fmt.Fprintf(w, "Requested file: %s", filepath)
}))

4. 中间件支持

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

func main() {
	r := goblin.NewRouter()
	r.Use(logger) // 全局中间件
	
	// 路由特定的中间件
	r.Methods(http.MethodGet).Handler("/admin", logger(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Admin page")
	})))
	
	http.ListenAndServe(":8080", r)
}

性能优化技巧

  1. 路由顺序:将最频繁访问的路由放在前面
  2. 减少通配符:过度使用通配符会影响性能
  3. 合理使用中间件:避免在中间件中进行耗时操作
  4. 路由分组:对相关路由进行分组管理

高级功能

路由分组

api := r.Group("/api")
api.Methods(http.MethodGet).Handler("/users", http.HandlerFunc(listUsers))
api.Methods(http.MethodPost).Handler("/users", http.HandlerFunc(createUser))

自定义404处理

r.NotFoundHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(w, "Custom 404 page")
}))

方法链式调用

r.Methods(http.MethodGet, http.MethodPost).
  Handler("/multi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		fmt.Fprintf(w, "GET request")
	case http.MethodPost:
		fmt.Fprintf(w, "POST request")
	}
}))

基准测试

Goblin在路由匹配性能上表现优异,特别是在路由数量较多时,Trie树的优势更加明显。以下是一个简单的基准测试比较:

func BenchmarkGoblin(b *testing.B) {
	r := goblin.NewRouter()
	r.Methods(http.MethodGet).Handler("/user/:id", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	
	req, _ := http.NewRequest(http.MethodGet, "/user/123", nil)
	
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		r.ServeHTTP(nil, req)
	}
}

在实际测试中,Goblin通常比标准库的http.ServeMux和其他一些流行路由库有更好的性能表现,特别是在路由规则复杂且数量大的情况下。

总结

Goblin是一个轻量级但功能强大的HTTP路由库,它通过Trie树数据结构实现了高效的路由匹配。对于需要高性能路由的项目,特别是那些有大量路由规则或对性能要求严格的场景,Goblin是一个值得考虑的选择。

它的API设计简洁,学习曲线平缓,同时提供了足够的功能满足大多数Web应用的需求。通过合理使用路由分组、中间件等特性,可以构建出结构清晰、性能优异的Web应用。

回到顶部