Gnet-Mux
一个基于 gnet/v2 的高性能 Web 框架,提供类似 Gin 的 API 风格。
功能特性
- 🚀 高性能: 基于
gnet/v2
的事件驱动架构
- 🎯 Gin风格API: 熟悉的路由和中间件设计
- 🛡️ 内置中间件: Logger、Recovery、CORS等
- 📝 丰富的响应方法: JSON、HTML、String、Redirect等
- 🔧 灵活的上下文: 支持参数获取、数据存储等
- 🛣️ 路径参数: 支持动态路由参数(如
/user/:id
)
- 🔄 自定义JSON: 支持第三方JSON序列化库(如
goccy/go-json
、json-iterator
)
- 🌐 WebSocket支持: 基于
gorilla/websocket
的 WebSocket 连接支持
快速开始
安装
go mod init your-project
go get -u gitlink.org.cn/nanakura/gnet-mux
基本用法
package main
import (
"gitlink.org.cn/nanakura/gnet-mux"
)
func main() {
// 创建默认引擎(包含日志和恢复中间件)
r := mux.Default()
// 定义路由
r.GET("/", func(c *mux.Context) {
c.JSON(map[string]string{
"message": "Hello, World!",
})
})
// 启动服务器
r.Run(":8080")
}
API 文档
创建引擎
// 创建空引擎
r := mux.New()
// 创建带默认中间件的引擎
r := mux.Default() // 包含 Logger() 和 Recovery()
路由注册
// 基本路由
r.GET("/", func(c *mux.Context) {
c.String("Hello, World!")
})
r.POST("/users", func(c *mux.Context) {
c.JSON(map[string]string{"message": "User created"})
})
// 路径参数路由
r.GET("/user/:id", func(c *mux.Context) {
id := c.Param("id")
c.JSON(map[string]interface{}{
"user_id": id,
"message": "User found",
})
})
// 多个路径参数
r.GET("/user/:id/post/:postId", func(c *mux.Context) {
userID := c.Param("id")
postID := c.Param("postId")
c.JSON(map[string]interface{}{
"user_id": userID,
"post_id": postID,
"message": "User post found",
})
})
// 混合静态路径和参数
r.GET("/api/v1/user/:id/profile", func(c *mux.Context) {
id := c.Param("id")
c.JSON(map[string]interface{}{
"user_id": id,
"profile": map[string]string{
"name": "John Doe",
"email": "john@example.com",
},
})
})
r.PUT("/users/:id", func(c *mux.Context) {
id := c.Param("id")
c.JSON(map[string]string{"id": id, "message": "User updated"})
})
r.DELETE("/users/:id", func(c *mux.Context) {
id := c.Param("id")
c.Status(204) // No Content
})
中间件
// 使用内置中间件
r.Use(mux.Logger())
r.Use(mux.Recovery())
r.Use(mux.CORS())
// 自定义中间件
r.Use(func(next mux.HandlerFunc) mux.HandlerFunc {
return func(c *mux.Context) {
// 前置处理
next(c)
// 后置处理
}
})
自定义JSON配置
框架支持使用第三方JSON序列化库,提供更好的性能或特定功能:
import (
mux "gnet-mux"
"github.com/goccy/go-json" // 高性能JSON库
// 或者使用 json-iterator
// jsoniter "github.com/json-iterator/go"
)
// 使用默认的 encoding/json
r1 := mux.New()
// 使用 goccy/go-json
r2 := mux.NewWithConfig(mux.Config{
JSONEncoder: json.Marshal,
JSONDecoder: json.Unmarshal,
})
// 使用 json-iterator
var jsonAPI = jsoniter.ConfigCompatibleWithStandardLibrary
r3 := mux.NewWithConfig(mux.Config{
JSONEncoder: jsonAPI.Marshal,
JSONDecoder: jsonAPI.Unmarshal,
})
配置选项:
JSONEncoder
: 自定义JSON编码函数,用于 c.JSON()
响应
JSONDecoder
: 自定义JSON解码函数,用于 c.ShouldBindJSON()
和 c.BindJSON()
XMLEncoder
: 自定义XML编码函数,用于 c.XML()
响应
YAMLEncoder
: 自定义YAML编码函数,用于 c.YAML()
响应
ProtoBufEncoder
: 自定义ProtoBuf编码函数,用于 c.ProtoBuf()
响应
- 如果不设置,将使用对应的标准库
自定义编码器配置
框架支持自定义各种格式的编码器:
import (
mux "gnet-mux"
"encoding/xml"
"gopkg.in/yaml.v3"
"google.golang.org/protobuf/proto"
)
// 使用自定义编码器
r := mux.NewWithConfig(mux.Config{
// 自定义JSON编码器
JSONEncoder: customJSONEncoder,
// 自定义XML编码器
XMLEncoder: xml.Marshal,
// 自定义YAML编码器
YAMLEncoder: yaml.Marshal,
// 自定义ProtoBuf编码器
ProtoBufEncoder: proto.Marshal,
})
// 示例:自定义JSON编码器,添加额外字段
func customJSONEncoder(v interface{}) ([]byte, error) {
wrapper := map[string]interface{}{
"data": v,
"timestamp": time.Now().Unix(),
"version": "1.0",
}
return json.Marshal(wrapper)
}
路径参数
框架支持动态路由参数,使用 :
前缀定义参数:
// 单个参数
r.GET("/user/:id", func(c *mux.Context) {
id := c.Param("id") // 获取路径参数
c.JSON(map[string]string{"user_id": id})
})
// 多个参数
r.GET("/user/:userId/post/:postId", func(c *mux.Context) {
userID := c.Param("userId")
postID := c.Param("postId")
c.JSON(map[string]string{
"user_id": userID,
"post_id": postID,
})
})
// 混合静态路径和参数
r.GET("/api/v1/user/:id/profile", func(c *mux.Context) {
id := c.Param("id")
// 处理用户资料请求
})
路由匹配规则:
- 静态路由优先于参数路由
- 参数名区分大小写
- 支持多级路径参数
- 路径参数不能为空
路由分组
框架支持路由分组,可以为一组路由设置共同的前缀和中间件:
// 基本分组
{
v1 := router.Group("/v1")
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}
// 带中间件的分组
{
v2 := router.Group("/v2")
v2.Use(AuthMiddleware())
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}
// 嵌套分组
api := router.Group("/api")
api.Use(APIMiddleware())
{
v1 := api.Group("/v1")
v1.Use(V1Middleware())
v1.GET("/users/:id", getUserHandler)
v1.POST("/users", createUserHandler)
}
// 分组中间件链式调用
admin := router.Group("/admin")
admin.Use(AuthMiddleware()).Use(AdminMiddleware())
admin.GET("/stats", adminStatsHandler)
分组特性:
- 支持路径前缀自动拼接
- 支持分组级别的中间件
- 支持嵌套分组
- 支持中间件链式调用
- 与 Gin 框架 API 完全兼容
模糊路由(通配符路由)
框架支持模糊路由(通配符路由),与 Gin 框架 API 完全兼容:
func InitRouter() *mux.Engine {
r := mux.New()
r.Use(mux.Logger())
r.Use(mux.Recovery())
r.GET("/foo/*any", someHandler)
return r
}
基本用法
// 通配符路由示例
router.GET("/foo/*any", func(c *mux.Context) {
any := c.Param("any")
c.JSON(mux.H{"any": any})
})
// API 通配符
router.GET("/api/*path", func(c *mux.Context) {
path := c.Param("path")
c.JSON(mux.H{"path": path})
})
// 静态文件服务
router.GET("/static/*filepath", func(c *mux.Context) {
filepath := c.Param("filepath")
// 处理静态文件请求
})
匹配示例
// 路由: /foo/*any
"/foo/bar" → any="bar"
"/foo/bar/baz" → any="bar/baz"
"/foo/bar/baz/qux" → any="bar/baz/qux"
"/foo/" → any=""
"/foo" → 不匹配(需要 /foo/ 或 /foo/something)
// 路由: /api/*path
"/api/users" → path="users"
"/api/users/123" → path="users/123"
"/api/posts/456/comments" → path="posts/456/comments"
路由优先级
通配符路由具有最低优先级,具体路由和参数路由优先匹配:
// 注册路由
router.GET("/api/*path", wildcardHandler) // 通配符路由
router.GET("/api/health", healthHandler) // 具体路由
router.GET("/api/users/:id", userHandler) // 参数路由
// 匹配结果
"/api/health" → 匹配 healthHandler(具体路由优先)
"/api/users/123" → 匹配 userHandler(参数路由优先)
"/api/other" → 匹配 wildcardHandler(通配符兜底)
模糊路由特性:
- 支持任意深度的路径匹配
- 自动处理空路径(trailing slash)
- 具体路由优先于通配符路由
- 参数路由优先于通配符路由
- 与 Gin 框架行为完全一致
- 适用于静态文件服务、API 兜底等场景
Cookie 管理
框架提供了完整的 Cookie 管理功能,与 Gin 框架 API 完全兼容:
// 获取 Cookie
cookie, err := c.Cookie("session_id")
if err != nil {
// Cookie 不存在
cookie = "default_value"
}
// 设置 Cookie
c.SetCookie(
"session_id", // name: Cookie 名称
"abc123", // value: Cookie 值
3600, // maxAge: 过期时间(秒)
"/", // path: 路径
"localhost", // domain: 域名
false, // secure: 是否仅 HTTPS
true, // httpOnly: 是否仅 HTTP(防止 XSS)
)
// Cookie 会话示例
router.GET("/login", func(c *mux.Context) {
username := c.Query("username")
c.SetCookie("user", username, 3600, "/", "", false, true)
c.JSON(mux.H{"message": "登录成功"})
})
router.GET("/profile", func(c *mux.Context) {
user, err := c.Cookie("user")
if err != nil {
c.JSON(mux.H{"error": "未登录"})
return
}
c.JSON(mux.H{"user": user})
})
// 删除 Cookie(设置过期时间为 -1)
c.SetCookie("session_id", "", -1, "/", "", false, true)
Cookie 特性:
- 支持获取和设置 Cookie
- 支持所有标准 Cookie 属性
- 自动处理路径默认值
- 与 Gin 框架 API 完全兼容
- 支持安全 Cookie 设置
静态文件服务
框架提供了完整的静态文件服务功能,与 Gin 框架 API 完全兼容:
// 静态目录服务
router.Static("/assets", "./assets")
// 自定义文件系统服务
router.StaticFS("/more_static", http.Dir("my_file_system"))
// 单个文件服务
router.StaticFile("/favicon.ico", "./resources/favicon.ico")
// 在处理器中发送文件
router.GET("/download", func(c *mux.Context) {
c.File("./files/document.pdf")
})
静态文件特性:
- 支持目录和单文件服务
- 自动 MIME 类型检测
- 安全路径检查(防止目录遍历攻击)
- 自动缓存头设置
- 支持自定义文件系统
- 目录索引文件支持(index.html)
- 与 Gin 框架 API 完全兼容
使用示例:
func main() {
router := mux.Default()
// 静态文件服务(完全遵循 Gin 示例)
router.Static("/assets", "./assets")
router.StaticFS("/more_static", http.Dir("my_file_system"))
router.StaticFile("/favicon.ico", "./resources/favicon.ico")
router.Run(":8080")
}
文件上传
框架提供了完整的文件上传功能,与 Gin 框架 API 完全兼容:
单文件上传
func main() {
router := mux.Default()
// 设置多部分表单的内存限制(默认为 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *mux.Context) {
// 单文件
file, _ := c.FormFile("file")
log.Println(file.Filename)
// 上传文件到指定目录
c.SaveUploadedFile(file, "./files/" + file.Filename)
c.Status(http.StatusOK).String(fmt.Sprintf("'%s' uploaded!", file.Filename))
})
router.Run(":8080")
}
多文件上传
router.POST("/upload/multiple", func(c *mux.Context) {
// 多部分表单
form, _ := c.MultipartForm()
files := form.File["files"]
for _, file := range files {
log.Println(file.Filename)
// 上传文件到指定目录
c.SaveUploadedFile(file, "./files/" + file.Filename)
}
c.Status(http.StatusOK).String(fmt.Sprintf("%d files uploaded!", len(files)))
})
文件上传特性:
- 支持单文件和多文件上传
- 可配置内存限制(MaxMultipartMemory)
- 自动创建目录结构
- 安全的文件保存
- 与 Gin 框架 API 完全兼容
- 支持大文件上传(超过内存限制时自动使用临时文件)
重要提示: file.Filename
不应该被信任。参考 MDN Content-Disposition 文档
上下文方法
获取请求数据
// URL 参数
id := c.Param("id")
// 查询参数
name := c.Query("name")
age := c.DefaultQuery("age", "18")
// 表单数据
username := c.PostForm("username")
password := c.DefaultPostForm("password", "")
// 文件上传
file, err := c.FormFile("file") // 单文件上传
form, err := c.MultipartForm() // 多文件上传
err := c.SaveUploadedFile(file, "./uploads/file") // 保存上传的文件
// 请求头
token := c.GetHeader("Authorization")
设置响应
// JSON 响应
c.JSON(map[string]interface{}{
"status": "success",
"data": data,
})
// XML 响应
c.XML(map[string]interface{}{
"status": "success",
"data": data,
})
// YAML 响应
c.YAML(map[string]interface{}{
"status": "success",
"data": data,
})
// Protocol Buffer 响应
c.ProtoBuf(protoMessage)
// 字符串响应
c.String("Hello, %s!", name)
// HTML 响应
c.HTML("<h1>Welcome</h1>")
// 原始数据响应
c.Data("application/octet-stream", []byte("binary data"))
// 从 Reader 读取数据响应
c.DataFromReader(http.StatusOK, contentLength, "text/plain", reader, extraHeaders)
// 重定向
c.Redirect(302, "/login")
// 设置状态码
c.Status(404).String("Not Found")
// 设置响应头
c.Header("X-Custom-Header", "value")
// Cookie 操作
cookie, err := c.Cookie("session_id") // 获取 Cookie
c.SetCookie("session_id", "abc123", 3600, "/", "localhost", false, true) // 设置 Cookie
JSON数据绑定
// JSON数据绑定
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
var user User
// 绑定JSON数据(使用配置的JSON解码器)
if err := c.ShouldBindJSON(&user); err != nil {
c.Status(400).JSON(map[string]string{"error": err.Error()})
return
}
// 绑定JSON数据并自动处理错误
if err := c.BindJSON(&user); err != nil {
return // 自动返回400错误
}
上下文存储
// 存储值
c.Set("user", user)
// 获取值
user, exists := c.Get("user")
user := c.MustGet("user") // 不存在时会 panic
中间件控制
// 执行下一个处理器
c.Next()
// 中止执行
c.Abort()
c.AbortWithStatus(403)
c.AbortWithStatusJSON(400, map[string]string{"error": "Bad Request"})
示例
完整示例
package main
import (
"net/http"
"gitlink.org.cn/nanakura/gnet-mux"
)
func main() {
r := mux.Default()
// 添加 CORS 中间件
r.Use(mux.CORS())
// 基本路由
r.GET("/", func(c *mux.Context) {
c.JSON(map[string]string{"message": "Hello, World!"})
})
// 带参数的路由
r.GET("/user/:id", func(c *mux.Context) {
id := c.Param("id")
c.JSON(map[string]string{"user_id": id})
})
// 查询参数
r.GET("/search", func(c *mux.Context) {
query := c.DefaultQuery("q", "")
page := c.DefaultQuery("page", "1")
c.JSON(map[string]string{
"query": query,
"page": page,
})
})
// POST 请求
r.POST("/user", func(c *mux.Context) {
name := c.PostForm("name")
email := c.PostForm("email")
if name == "" {
c.AbortWithStatusJSON(http.StatusBadRequest,
map[string]string{"error": "Name is required"})
return
}
c.JSON(map[string]interface{}{
"message": "User created",
"user": map[string]string{
"name": name,
"email": email,
},
})
})
// 启动服务器
r.Run(":8080")
}
自定义中间件示例
// 认证中间件
func AuthMiddleware() mux.Middleware {
return func(next mux.HandlerFunc) mux.HandlerFunc {
return func(c *mux.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(401, map[string]string{
"error": "Authorization header required",
})
return
}
// 验证 token 逻辑...
c.Set("user_id", "123")
next(c)
}
}
}
// 使用中间件
r.Use(AuthMiddleware())
性能
基于 gnet/v2 的高性能网络引擎,相比传统的 net/http 具有更好的性能表现:
- 更低的内存占用
- 更高的并发处理能力
- 更少的 GC 压力
- 支持多核并行处理
与 Gin 的对比
特性 |
Gnet-Mux |
Gin |
网络引擎 |
gnet/v2 |
net/http |
性能 |
更高 |
标准 |
API 风格 |
类似 Gin |
原生 |
中间件 |
支持 |
支持 |
生态系统 |
新兴 |
成熟 |
WebSocket 支持
框架支持 WebSocket 连接,使用 gorilla/websocket
库:
import (
"github.com/gorilla/websocket"
mux "gitlink.org.cn/nanakura/gnet-mux"
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func handleWebSocket(c *mux.Context) {
// 升级 HTTP 连接为 WebSocket 连接
conn, err := c.UpgradeWebSocket(&upgrader)
if err != nil {
return
}
defer conn.Close()
// 处理 WebSocket 消息
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
break
}
// 回显消息
err = conn.WriteMessage(messageType, message)
if err != nil {
break
}
}
}
// 注册 WebSocket 路由
r.GET("/ws", handleWebSocket)
WebSocket 特性:
- 支持
gorilla/websocket
库
- 提供
c.Writer()
和 c.Request()
方法用于 WebSocket 升级
- 提供
c.UpgradeWebSocket()
便捷方法
- 与 Gin 框架 API 完全兼容
- 支持自定义 WebSocket 升级器配置
注意事项
- 这是一个基于 gnet/v2 的实验性框架
- API 可能会在后续版本中发生变化
- 建议在生产环境使用前进行充分测试
贡献
欢迎提交 Issue 和 Pull Request!
许可证
MIT License
Gnet-Mux
一个基于 gnet/v2 的高性能 Web 框架,提供类似 Gin 的 API 风格。
功能特性
gnet/v2
的事件驱动架构/user/:id
)goccy/go-json
、json-iterator
)gorilla/websocket
的 WebSocket 连接支持快速开始
安装
基本用法
API 文档
创建引擎
路由注册
中间件
自定义JSON配置
框架支持使用第三方JSON序列化库,提供更好的性能或特定功能:
配置选项:
JSONEncoder
: 自定义JSON编码函数,用于c.JSON()
响应JSONDecoder
: 自定义JSON解码函数,用于c.ShouldBindJSON()
和c.BindJSON()
XMLEncoder
: 自定义XML编码函数,用于c.XML()
响应YAMLEncoder
: 自定义YAML编码函数,用于c.YAML()
响应ProtoBufEncoder
: 自定义ProtoBuf编码函数,用于c.ProtoBuf()
响应自定义编码器配置
框架支持自定义各种格式的编码器:
路径参数
框架支持动态路由参数,使用
:
前缀定义参数:路由匹配规则:
路由分组
框架支持路由分组,可以为一组路由设置共同的前缀和中间件:
分组特性:
模糊路由(通配符路由)
框架支持模糊路由(通配符路由),与 Gin 框架 API 完全兼容:
基本用法
匹配示例
路由优先级
通配符路由具有最低优先级,具体路由和参数路由优先匹配:
模糊路由特性:
Cookie 管理
框架提供了完整的 Cookie 管理功能,与 Gin 框架 API 完全兼容:
Cookie 特性:
静态文件服务
框架提供了完整的静态文件服务功能,与 Gin 框架 API 完全兼容:
静态文件特性:
使用示例:
文件上传
框架提供了完整的文件上传功能,与 Gin 框架 API 完全兼容:
单文件上传
多文件上传
文件上传特性:
重要提示:
file.Filename
不应该被信任。参考 MDN Content-Disposition 文档上下文方法
获取请求数据
设置响应
JSON数据绑定
上下文存储
中间件控制
示例
完整示例
自定义中间件示例
性能
基于 gnet/v2 的高性能网络引擎,相比传统的 net/http 具有更好的性能表现:
与 Gin 的对比
WebSocket 支持
框架支持 WebSocket 连接,使用
gorilla/websocket
库:WebSocket 特性:
gorilla/websocket
库c.Writer()
和c.Request()
方法用于 WebSocket 升级c.UpgradeWebSocket()
便捷方法注意事项
贡献
欢迎提交 Issue 和 Pull Request!
许可证
MIT License