ginx

package module
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 6, 2026 License: MIT Imports: 16 Imported by: 0

README

ginx

Go Version Go Reference License Coverage

基于 Gin 的工业级 HTTPS Server 组件库

一套 API,多通道 TLS 服务 —— HTTP/2、HTTP/3 (QUIC)、Unix Socket 同时监听


📖 目录


🎯 设计理念

ginx 将 Gin 引擎完全封装在内部,对外暴露纯接口与配置结构体,实现 框架与业务的彻底解耦

为什么选择 ginx?
场景 直接使用 Gin 使用 ginx
更换 Web 框架 修改所有 Handler 签名 仅修改 ginx 内部实现
多通道监听 自行实现 TCP+TLS+QUIC+Unix 一行链式调用
统一日志/错误格式 自行封装中间件 开箱即用
团队规范约束 依靠 Code Review 编译器强制
编码铁律
  1. 绝不 panic —— 唯一 recover()middleware/recovery.go
  2. 绝不吞错 —— 所有 error 必须上报或累加
  3. 不导出 Gin 类型 —— HandlerFunc 是唯一暴露的 Gin 别名
  4. Start() 后不可变 —— 链式配置在启动后调用仅记录 Warn 日志

✨ 核心特性

  • 🔒 强制 TLS —— 所有通道必须配置证书,拒绝明文传输
  • 🌐 多通道监听 —— HTTP/2 (TLS over TCP)、HTTP/3 (QUIC over UDP)、Unix Domain Socket 可同时开启
  • 🔗 链式 API —— 流畅的 Builder 模式,配置即文档
  • 🧱 内置中间件 —— Recovery、RequestID、Timeout、CORS、Validation、RateLimit 开箱即用
  • 📊 标准化响应 —— 统一的 JSON 响应格式 {code, msg, data, requestId, timestamp}
  • 🩺 健康检查 —— 自动注册 /health 端点,可通过配置自定义路径
  • 🛡️ IP 限流 —— 基于令牌桶的 per-IP 限流,支持白名单
  • 🪵 可插拔日志 —— 通过 Logger 接口接入任意日志库(Zap、Zerolog、Logrus 等)
  • 🧹 优雅关闭 —— 支持 SIGINT/SIGTERM 信号捕获与 Stop() 主动关闭
  • 🪟 跨平台 —— Linux / macOS / Windows(Unix Socket 需 Windows 10 build 17063+)
  • 🧪 高覆盖率 —— 83.8% 测试覆盖率 + -race 零告警

🚀 快速开始

30 秒运行第一个 ginx 服务
package main

import (
    "time"

    "github.com/gin-gonic/gin"
    "github.com/lcylpzls/ginx"
)

func main() {
    err := ginx.NewServer(ginx.Config{
        TLSCertFile:     "/etc/ssl/certs/server.crt",
        TLSKeyFile:      "/etc/ssl/private/server.key",
        ShutdownTimeout: 30 * time.Second,
        RequestTimeout:  30 * time.Second,
    }).
        UseHttp2Listen(":8443").
        RegisterRoute(ginx.Route{
            Method: "GET",
            Path:   "/ping",
            Handler: func(c *gin.Context) {
                c.JSON(200, ginx.StandardizedResponse{
                    Code:      ginx.CodeSuccess,
                    Msg:       "pong",
                    RequestID: c.GetString("requestId"),
                    Timestamp: time.Now().UnixMilli(),
                })
            },
        }).
        Start()

    if err != nil {
        panic(err)
    }
}
# 生成自签名证书(开发环境)
bash gen_cert.sh

# 运行
go run main.go

# 测试
curl -k https://localhost:8443/ping
# {"code":0,"msg":"pong","requestId":"...","timestamp":...}

curl -k https://localhost:8443/health
# {"code":0,"msg":"ok","data":{"status":"运行中","uptime":"30秒","started":"..."},...}

📦 安装

go get github.com/lcylpzls/ginx@latest

依赖项:

依赖 用途
github.com/gin-gonic/gin HTTP 引擎
github.com/quic-go/quic-go HTTP/3 (QUIC) 协议支持

要求 Go ≥ 1.21。


🏗️ 架构概览

┌─────────────────────────────────────────────────┐
│                    ginx.Server                    │
│  ┌─────────────────────────────────────────────┐│
│  │              Chain API (Builder)             ││
│  │  WithLogger → UseHttp2Listen → UseHttp3Listen││
│  │  → RegisterRoute → EnableRateLimit → Start  ││
│  └──────────────────┬──────────────────────────┘│
│                     │ Start()                     │
│         ┌───────────┼───────────┐                │
│         ▼           ▼           ▼                │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐         │
│  │ HTTP/2   │ │ HTTP/3   │ │  Unix    │         │
│  │ TLS:TCP  │ │ QUIC:UDP │ │  Socket  │         │
│  └────┬─────┘ └────┬─────┘ └────┬─────┘         │
│       │            │            │                │
│       └────────────┼────────────┘                │
│                    ▼                             │
│         ┌─────────────────────┐                  │
│         │    gin.Engine        │                  │
│         │  ┌───────────────┐   │                  │
│         │  │  Middleware    │   │                  │
│         │  │  Chain         │   │                  │
│         │  │  Recovery      │   │                  │
│         │  │  RequestID     │   │                  │
│         │  │  Timeout       │   │                  │
│         │  │  CORS          │   │                  │
│         │  │  Validation    │   │                  │
│         │  │  RateLimit     │   │                  │
│         │  ├───────────────┤   │                  │
│         │  │  Routes        │   │                  │
│         │  │  /health       │   │                  │
│         │  └───────────────┘   │                  │
│         └─────────────────────┘                  │
└─────────────────────────────────────────────────┘

📚 使用指南

1. 基础用法
package main

import (
    "time"
    "github.com/lcylpzls/ginx"
)

func main() {
    s := ginx.NewServer(ginx.Config{
        TLSCertFile:     "/path/to/cert.pem",
        TLSKeyFile:      "/path/to/key.pem",
        ShutdownTimeout: 30 * time.Second,
        RequestTimeout:  30 * time.Second,
    })

    s.UseHttp2Listen(":8443")

    if err := s.Start(); err != nil {
        panic(err)
    }
}
2. 链式 API 配置

所有配置方法均返回 *Server,支持流畅的链式调用:

err := ginx.NewServer(cfg).
    WithLogger(myLogger).              // 注入自定义 Logger
    UseHttp2Listen(":8443").           // 启用 HTTP/2
    UseHttp3Listen(":8443").           // 启用 HTTP/3(同端口,TCP/UDP 不冲突)
    UseGlobalMiddleware(authMiddleware).// 全局中间件
    DisableMiddleware(ginx.MiddlewareValidation). // 禁用校验中间件
    OverrideMiddleware(ginx.MiddlewareRequestID, customRequestID). // 覆盖中间件
    RegisterRoute(ginx.Route{...}).    // 注册单条路由
    RegisterRoutes([]ginx.Route{...}). // 批量注册路由
    RegisterRouteGroup("/api", func(rg *ginx.RouteGroup) { // 路由分组
        rg.GET("/users", listUsers)
    }).
    EnableRateLimit(ginx.RateLimitOptions{ // IP 限流
        QPS:    100,
        Window: time.Second,
    }).
    Start()

⚠️ 重要: 在 Start() 之后调用链式方法不会 panic,但会通过 Logger 输出 Warn 警告并忽略修改。

3. 多通道监听

ginx 支持同时启用多种监听通道:

s := ginx.NewServer(cfg).
    UseHttp2Listen("0.0.0.0:443").            // HTTPS — 对外服务
    UseHttp3Listen("0.0.0.0:443").            // HTTP/3 QUIC — 同端口
    UseUnixSocketListen("/run/app.sock", 0660) // Unix Socket — 本地通信
方法 协议 传输层 典型场景
UseHttp2Listen(addr) HTTP/1.1 + HTTP/2 TLS over TCP 对外 API 服务
UseHttp3Listen(addr) HTTP/3 QUIC over UDP 移动端/弱网优化
UseUnixSocketListen(path, perm) HTTP/1.1 Unix Domain Socket 本地 Nginx 反向代理
4. 路由注册
单条路由
s.RegisterRoute(ginx.Route{
    Method: "GET",
    Path:   "/api/users/:id",
    Handler: func(c *gin.Context) {
        userID := c.Param("id")
        c.JSON(200, ginx.StandardizedResponse{
            Code:      ginx.CodeSuccess,
            Msg:       "ok",
            Data:      map[string]string{"id": userID},
            RequestID: c.GetString("requestId"),
            Timestamp: time.Now().UnixMilli(),
        })
    },
    Middleware: []ginx.HandlerFunc{authMiddleware}, // 路由专属中间件(可选)
})
批量注册
s.RegisterRoutes([]ginx.Route{
    {Method: "GET",  Path: "/api/users",    Handler: listUsers},
    {Method: "POST", Path: "/api/users",    Handler: createUser},
    {Method: "PUT",  Path: "/api/users/:id", Handler: updateUser},
})
5. 路由分组
s.RegisterRouteGroup("/api/v2", func(rg *ginx.RouteGroup) {
    // 分组级中间件
    rg.Use(authMiddleware, rateLimitMiddleware)

    // 子路由
    rg.GET("/products", listProducts)
    rg.POST("/products", createProduct)

    // 嵌套分组
    admin := rg.Group("/admin")
    admin.GET("/stats", getStats)
})
6. 中间件管理
内置中间件开关

通过 Config 控制:

cfg := ginx.Config{
    MiddlewareRecovery:   true,  // 默认开启
    MiddlewareRequestID:  true,  // 默认开启
    MiddlewareTimeout:    true,  // 默认开启
    MiddlewareCORS:       true,  // 默认开启
    MiddlewareValidation: true,  // 默认开启
}
运行时控制
// 禁用
s.DisableMiddleware(ginx.MiddlewareValidation, ginx.MiddlewareCORS)

// 重新启用(RateLimit 除外)
s.EnableMiddleware(ginx.MiddlewareValidation)

// 覆盖内置实现
s.OverrideMiddleware(ginx.MiddlewareRequestID, myCustomRequestID)

// 追加全局中间件(追加到链末尾)
s.UseGlobalMiddleware(loggingMiddleware, metricsMiddleware)
中间件执行顺序
RequestID → CORS → Recovery → Timeout → Validation → RateLimit → Handler
                                                                    ↑
                                              全局中间件(UseGlobalMiddleware)
7. 自定义 Logger

实现 ginx.Logger 接口即可接入任意日志库:

// 使用 Zap 的示例
type ZapLogger struct {
    logger *zap.Logger
}

func (l *ZapLogger) Debug(ctx context.Context, msg string, fields ...ginx.Field) {
    l.logger.Debug(msg, toZapFields(fields)...)
}
func (l *ZapLogger) Info(ctx context.Context, msg string, fields ...ginx.Field) {
    l.logger.Info(msg, toZapFields(fields)...)
}
func (l *ZapLogger) Warn(ctx context.Context, msg string, fields ...ginx.Field) {
    l.logger.Warn(msg, toZapFields(fields)...)
}
func (l *ZapLogger) Error(ctx context.Context, msg string, fields ...ginx.Field) {
    l.logger.Error(msg, toZapFields(fields)...)
}
func (l *ZapLogger) Fatal(ctx context.Context, msg string, fields ...ginx.Field) {
    l.logger.Fatal(msg, toZapFields(fields)...)
}

// 注入
s.WithLogger(&ZapLogger{logger: zapLogger})

日志字段构建器:

ginx.StringField("path", "/api/users")
ginx.IntField("status", 200)
ginx.DurationField("latency", elapsed)
ginx.ErrorField(err)
ginx.AnyField("body", data)
8. IP 限流

基于令牌桶算法的 per-IP 限流,支持 CIDR 白名单:

s.EnableRateLimit(ginx.RateLimitOptions{
    QPS:     100,              // 每 IP 每秒允许的请求数
    Window:  time.Second,      // 限流窗口
    Whitelist: []string{       // 白名单(IP 或 CIDR)
        "10.0.0.0/8",
        "127.0.0.1",
    },
    CleanupInterval: 5 * time.Minute, // 过期桶清理间隔
})

客户端 IP 提取优先级: X-Forwarded-For > X-Real-IP > RemoteAddr

9. 健康检查

ginx 自动注册健康检查端点,默认路径 /health

// 自定义路径
cfg := ginx.Config{
    HealthPath: "/api/healthz",
}

// 若自定义路径与业务路由冲突,业务路由优先
s.RegisterRoute(ginx.Route{
    Method: "GET",
    Path:   "/api/healthz",  // 覆盖内置健康检查
    Handler: customHealthHandler,
})

响应示例:

{
    "code": 0,
    "msg": "ok",
    "data": {
        "status": "运行中",
        "uptime": "2小时30分钟",
        "started": "2026-06-06T10:00:00+08:00"
    },
    "requestId": "",
    "timestamp": 1749200400000
}
10. 优雅关闭
主动关闭
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

if err := s.Stop(ctx); err != nil {
    log.Printf("关闭服务出错:%v", err)
}
信号关闭(Start 内置)

Start() 内部已注册 SIGINT/SIGTERM 信号处理,收到信号后自动执行优雅关闭:

// Start() 内部流程:
// 1. 创建 Listener
// 2. 启动 HTTP Server goroutine
// 3. 注册 signal.Notify(quit, SIGINT, SIGTERM)
// 4. 阻塞等待信号或 ctx.Done()
// 5. 收到信号 → Shutdown 所有 HTTP Server
// 6. Close 所有 Listener
// 7. 清理 Unix Socket 文件
// 8. 执行 cleanupFuncs
独立使用 GracefulShutdown
ginx.GracefulShutdown(
    ctx,
    logger,
    httpServer,
    listener,
    30*time.Second,    // shutdownTimeout
    "/run/app.sock",   // unixSocketPath(空字符串表示不清理)
    cleanupFuncs,
)
11. 静态文件服务与 SPA

ginx 支持从本地目录或 Go embed.FS 提供静态文件,并内置 SPA 回退模式(未匹配的 GET 请求自动返回 index.html)。

本地目录
s := ginx.NewServer(cfg).
    UseHttp2Listen(":443").
    ServeStaticDir("/assets", "./public").  // 等价于 gin.Static()
    RegisterRoute(ginx.Route{
        Method: "GET", Path: "/api/hello",
        Handler: helloHandler,
    })
嵌入式文件系统(embed.FS)
//go:embed all:frontend/dist
var distFS embed.FS

func main() {
    s := ginx.NewServer(cfg).
        UseHttp2Listen(":443").
        ServeStaticFS("/", http.FS(distFS)).  // 等价于 gin.StaticFS()
        RegisterRoute(...).
        Start()
}
SPA 模式

当使用 Vue Router / React Router 等客户端路由时,浏览器直接访问 /dashboard 在服务端没有对应文件,需要回退到 index.html

//go:embed all:frontend/dist
var spaAssets embed.FS

func main() {
    distFS, _ := fs.Sub(spaAssets, "frontend/dist")

    err := ginx.NewServer(cfg).
        UseHttp2Listen(":443").
        ServeStaticFS("/", http.FS(distFS)).        // 提供所有静态文件
        EnableSPA(http.FS(distFS), "index.html").     // SPA 回退
        RegisterRoute(ginx.Route{
            Method: "GET", Path: "/api/hello",
            Handler: helloHandler,
        }).
        Start()
}

SPA 回退规则:仅对未匹配的 GET/HEAD 请求返回 index.html。POST/PUT/DELETE 等非 GET/HEAD 请求仍返回标准 JSON 404/405 响应。API 路由优先于 SPA 回退。

多静态前缀

同时提供多个静态目录或文件系统:

s.ServeStaticDir("/docs", "./public/docs").
  ServeStaticFS("/admin", http.FS(adminFS)).
  ServeStaticFS("/", http.FS(distFS)).
  EnableSPA(http.FS(distFS), "index.html")

注意ServeStaticDir 使用 http.Dir 实现,在 Linux 下与 SPA 的 EnableSPA 无冲突。各前缀通过 gin 的 radix tree 独立路由,互不干扰。


📋 API 参考

核心函数
函数 说明
NewServer(cfg Config) *Server 创建 Server 实例
GracefulShutdown(ctx, logger, srv, ln, timeout, sockPath, cleanups) error 独立优雅关闭函数
Server 方法
生命周期
方法 说明
Start() error 启动服务(阻塞,直到收到信号或错误)
Stop(ctx context.Context) error 优雅关闭(sync.Once 保护,可重复调用)
ListenerAddr() string 返回首个 Listener 的监听地址(线程安全)
链式配置
方法 说明
WithLogger(l Logger) *Server 注入自定义 Logger 实现
UseHttp2Listen(addr string) *Server 启用 HTTP/2 TLS 监听
UseHttp3Listen(addr string) *Server 启用 HTTP/3 QUIC 监听
UseUnixSocketListen(path string, perm os.FileMode) *Server 启用 Unix Domain Socket 监听
RegisterRoute(r Route) *Server 注册单条路由
RegisterRoutes(routes []Route) *Server 批量注册路由
RegisterRouteGroup(prefix string, fn func(*RouteGroup)) *Server 注册路由分组
UseGlobalMiddleware(mw ...HandlerFunc) *Server 追加全局中间件
OverrideMiddleware(mt MiddlewareType, mw HandlerFunc) *Server 覆盖内置中间件实现
DisableMiddleware(mt ...MiddlewareType) *Server 禁用内置中间件
EnableMiddleware(mt ...MiddlewareType) *Server 启用内置中间件(RateLimit 需用 EnableRateLimit)
EnableRateLimit(opts RateLimitOptions) *Server 启用 IP 令牌桶限流
DisableRateLimit() *Server 禁用 IP 限流
ServeStaticDir(prefix, root string) *Server 从本地目录提供静态文件
ServeStaticFS(prefix string, fs http.FileSystem) *Server 从 http.FileSystem 提供静态文件(支持 embed.FS)
EnableSPA(fs http.FileSystem, indexPath string) *Server 启用 SPA 回退模式
数据类型
Config

全部配置项的结构体,详见 配置参考

Route
type Route struct {
    Method     string          // HTTP 方法
    Path       string          // 路由路径
    Handler    HandlerFunc     // 处理器
    Middleware []HandlerFunc   // 路由专属中间件(可选)
}
RouteGroup

路由分组,支持嵌套和分组级中间件。

rg.GET(path, handler, mw...)     // GET
rg.POST(path, handler, mw...)    // POST
rg.PUT(path, handler, mw...)     // PUT
rg.DELETE(path, handler, mw...)  // DELETE
rg.PATCH(path, handler, mw...)   // PATCH
rg.Use(mw...)                    // 中间件
rg.Group(relativePath) *RouteGroup // 子分组
StandardizedResponse

统一的 JSON 响应体:

type StandardizedResponse struct {
    Code      int    `json:"code"`
    Msg       string `json:"msg"`
    Data      any    `json:"data,omitempty"`
    RequestID string `json:"requestId"`
    Timestamp int64  `json:"timestamp"`
}
HandlerFunc
type HandlerFunc = gin.HandlerFunc  // ginx 暴露的唯一 Gin 类型别名
MiddlewareType
type MiddlewareType string

const (
    MiddlewareRequestID  MiddlewareType = "request_id"
    MiddlewareCORS       MiddlewareType = "cors"
    MiddlewareTimeout    MiddlewareType = "timeout"
    MiddlewareRecovery   MiddlewareType = "recovery"
    MiddlewareValidation MiddlewareType = "validation"
    MiddlewareRateLimit  MiddlewareType = "rate_limit"
)
RateLimitOptions
type RateLimitOptions struct {
    QPS             int           // 每 IP 每秒请求数(必填,> 0)
    Window          time.Duration // 限流窗口(必填,> 0)
    Whitelist       []string      // IP/CIDR 白名单(可选)
    CleanupInterval time.Duration // 过期桶清理间隔(可选,默认 5 分钟)
}
日志接口
type Logger interface {
    Debug(ctx context.Context, msg string, fields ...Field)
    Info(ctx context.Context, msg string, fields ...Field)
    Warn(ctx context.Context, msg string, fields ...Field)
    Error(ctx context.Context, msg string, fields ...Field)
    Fatal(ctx context.Context, msg string, fields ...Field)
}

type Field struct {
    Key   string
    Value any
}

// 字段构建器
func StringField(key, val string) Field
func IntField(key string, val int) Field
func DurationField(key string, val time.Duration) Field
func ErrorField(err error) Field
func AnyField(key string, val any) Field

NoopLogger 是默认的空实现,所有方法不执行任何操作。


⚙️ 配置参考

type Config struct {
    // === TLS 证书(必填)===
    TLSCertFile string   // TLS 证书文件路径(PEM 格式)
    TLSKeyFile  string   // TLS 私钥文件路径(PEM 格式)

    // === 超时 ===
    ReadTimeout     time.Duration // HTTP 读取超时
    WriteTimeout    time.Duration // HTTP 写入超时
    IdleTimeout     time.Duration // 空闲连接超时
    RequestTimeout  time.Duration // 请求处理超时(Timeout 中间件使用)
    ShutdownTimeout time.Duration // 优雅关闭最大等待时间

    // === HTTP ===
    MaxHeaderBytes int    // 请求头最大字节数
    HealthPath     string // 健康检查路径(默认 "/health")
    LogLevel       string // 日志级别:debug/info/warn/error(默认 "info")
    LogSuccessReq  bool   // 是否记录成功请求

    // === CORS ===
    CORSAllowedOrigins []string      // 允许的来源
    CORSAllowedMethods []string      // 允许的 HTTP 方法
    CORSAllowedHeaders []string      // 允许的请求头
    CORSMaxAge         time.Duration // 预检请求缓存时间

    // === 中间件开关 ===
    MiddlewareRequestID  bool // RequestID 中间件
    MiddlewareCORS       bool // CORS 中间件
    MiddlewareTimeout    bool // Timeout 中间件
    MiddlewareRecovery   bool // Recovery 中间件
    MiddlewareValidation bool // Validation 中间件
}
状态码常量
常量 说明
CodeSuccess 0 请求成功
CodeBadRequest 400 请求参数校验失败
CodeNotFound 404 请求的资源不存在
CodeMethodNotAllowed 405 不支持的请求方法
CodeTooManyRequests 429 请求频率超限
CodeInternalError 500 服务器内部错误
CodeServiceUnavailable 503 服务暂时不可用(超时)

🧩 内置中间件

中间件 类型标识 说明 默认
Recovery MiddlewareRecovery Panic 捕获,返回 500 + 堆栈日志 启用
RequestID MiddlewareRequestID 生成 UUID v4 格式请求 ID,设置 X-Request-ID 响应头 启用
Timeout MiddlewareTimeout 请求超时控制,超时返回 503,使用自定义 ResponseWriter 无 data race 启用
CORS MiddlewareCORS 跨域处理,通过 Config 配置规则 启用
Validation MiddlewareValidation POST/PUT/PATCH 请求体 JSON 格式校验,跳过 GET/HEAD/OPTIONS 启用
RateLimit MiddlewareRateLimit IP 令牌桶限流,需通过 EnableRateLimit() 显式开启 关闭

📊 响应规范

所有响应(包括 404/405/429/500/503)均使用 StandardizedResponse 格式:

正常响应
{
    "code": 0,
    "msg": "ok",
    "data": {"id": "123", "name": "Alice"},
    "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "timestamp": 1749200400000
}
异常响应对照
HTTP 状态码 code msg 触发条件
400 400 请求参数校验失败 Validation 中间件拦截
404 404 请求的资源不存在 路径无匹配路由
405 405 不支持的请求方法 方法不匹配(需 HandleMethodNotAllowed=true
429 429 RateLimit 超限
500 500 服务器内部错误 Panic 被 Recovery 捕获
503 503 请求处理超时 Timeout 中间件超时

💡 最佳实践

1. 证书管理
# 开发/测试环境:使用项目自带脚本生成自签名证书
bash gen_cert.sh

# 生产环境:使用 Let's Encrypt 或企业 CA 签发的证书
# 确保证书文件权限为 600
chmod 600 /etc/ssl/private/server.key
2. 在 Handler 中获取 RequestID
func myHandler(c *gin.Context) {
    requestID := c.GetString("requestId")
    // 用于日志追踪和响应
}
3. 使用响应常量
// ✅ 推荐:使用 ginx 提供的状态码常量
c.JSON(http.StatusBadRequest, ginx.StandardizedResponse{
    Code:      ginx.CodeBadRequest,
    Msg:       "参数校验失败:" + err.Error(),
    RequestID: c.GetString("requestId"),
    Timestamp: time.Now().UnixMilli(),
})

// ❌ 避免:硬编码数字
c.JSON(400, ginx.StandardizedResponse{Code: 400, ...})
4. 生产环境配置参考
cfg := ginx.Config{
    TLSCertFile:          "/etc/ssl/certs/prod.crt",
    TLSKeyFile:           "/etc/ssl/private/prod.key",
    ReadTimeout:          10 * time.Second,
    WriteTimeout:         30 * time.Second,
    IdleTimeout:          120 * time.Second,
    RequestTimeout:       30 * time.Second,
    ShutdownTimeout:      30 * time.Second,
    MaxHeaderBytes:       1 << 20, // 1 MB
    HealthPath:           "/healthz",
    LogLevel:             "info",
    LogSuccessReq:        false,
    MiddlewareRecovery:   true,
    MiddlewareRequestID:  true,
    MiddlewareTimeout:    true,
    MiddlewareCORS:       true,
    MiddlewareValidation: true,
    CORSAllowedOrigins:   []string{"https://example.com"},
    CORSAllowedMethods:   []string{"GET", "POST", "PUT", "DELETE"},
    CORSAllowedHeaders:   []string{"Content-Type", "Authorization"},
    CORSMaxAge:           12 * time.Hour,
}
5. 框架解耦
// ✅ ginx 使用 HandlerFunc = gin.HandlerFunc 别名
// 当未来切换底层框架时,只需修改 ginx 内部的类型映射
// 调用方代码无需改动(只要不直接 import gin)
func myHandler(c *gin.Context) {
    c.JSON(200, ginx.StandardizedResponse{...})
}

📝 版本历史

版本 日期 里程碑
v0.9.0 2026-06 Timeout Data Race 修复、panic → Warn 日志、83.8% 覆盖率
v0.4.0 2026-06 Stop() 吞错修复、链式方法并发控制、Handler 私有化
v0.3.0 Windows AF_UNIX 兼容性支持
v0.2.0 多通道 TLS/HTTP3/Unix Socket Listener
v0.1.0 初始版本:Gin 封装 + 中间件管理

📄 许可证

MIT


⭐ 如果这个项目对你有帮助,请给一个 Star!

Documentation

Overview

Package ginx 提供基于 Gin 的工业级解耦 HTTPS Server 组件库。

ginx 将 Gin 引擎完全封装在内部,对外暴露接口与配置,实现框架与业务的彻底解耦。 三方调用方无需直接依赖 Gin,仅需导入本包即可构建生产级 HTTPS 服务。

v0.2.0 起强制 TLS,支持 HTTP/2、HTTP/3 (QUIC) 和 Unix Socket 多通道同时监听。

Index

Constants

View Source
const (
	// CodeSuccess 表示请求成功。
	CodeSuccess = 0

	// CodeBadRequest 表示请求参数校验失败。
	CodeBadRequest = 400

	// CodeNotFound 表示请求的资源不存在。
	CodeNotFound = 404

	// CodeMethodNotAllowed 表示不支持的请求方法。
	CodeMethodNotAllowed = 405

	// CodeTooManyRequests 表示请求频率超限。
	CodeTooManyRequests = 429

	// CodeInternalError 表示服务器内部错误。
	CodeInternalError = 500

	// CodeServiceUnavailable 表示服务暂时不可用(如请求超时)。
	CodeServiceUnavailable = 503
)

HTTP 状态码常量。

Variables

This section is empty.

Functions

func GracefulShutdown

func GracefulShutdown(
	ctx context.Context,
	logger Logger,
	httpServer *http.Server,
	listener net.Listener,
	shutdownTimeout time.Duration,
	unixSocketPath string,
	cleanupFuncs []func(),
) error

GracefulShutdown 监听系统信号并执行优雅关闭。

收到 SIGINT 或 SIGTERM 后,调用 httpServer.Shutdown(ctx) 排空请求, 清理 Unix Socket 文件(如适用),最后调用 cleanup 函数。 返回 nil 表示正常关闭,返回 error 表示关闭超时或异常。

注意:v0.2.0 起,此函数仅作为公开 API 保留,Server.Start() 内部已内联信号处理。 调用方如需自定义关闭逻辑可使用此函数。

Types

type Config

type Config struct {
	// TLSCertFile TLS 证书文件路径(PEM 格式),必填。
	// 文件必须存在且为普通文件(不可为目录)。
	TLSCertFile string

	// TLSKeyFile TLS 私钥文件路径(PEM 格式),必填。
	// 文件必须存在且为普通文件(不可为目录)。
	TLSKeyFile string

	// ReadTimeout HTTP 读取超时时间。
	ReadTimeout time.Duration

	// WriteTimeout HTTP 写入超时时间。
	WriteTimeout time.Duration

	// IdleTimeout HTTP 空闲连接超时时间。
	IdleTimeout time.Duration

	// RequestTimeout 单个请求的超时时间,由 Timeout 中间件使用。
	RequestTimeout time.Duration

	// ShutdownTimeout 优雅关闭的最大等待时间。
	ShutdownTimeout time.Duration

	// MaxHeaderBytes 请求头的最大字节数。
	MaxHeaderBytes int

	// HealthPath 健康检查端点路径,默认为 "/health"。
	HealthPath string

	// LogLevel 日志级别,可选 "debug"、"info"、"warn"、"error",为空则默认 "info"。
	LogLevel string

	// LogSuccessReq 是否记录成功请求的日志。
	LogSuccessReq bool

	// CORSAllowedOrigins CORS 允许的来源列表。
	CORSAllowedOrigins []string

	// CORSAllowedMethods CORS 允许的 HTTP 方法列表。
	CORSAllowedMethods []string

	// CORSAllowedHeaders CORS 允许的请求头列表。
	CORSAllowedHeaders []string

	// CORSMaxAge CORS 预检请求的缓存时间。
	CORSMaxAge time.Duration

	// MiddlewareRequestID 是否启用 RequestID 中间件。
	MiddlewareRequestID bool

	// MiddlewareCORS 是否启用 CORS 中间件。
	MiddlewareCORS bool

	// MiddlewareTimeout 是否启用 Timeout 中间件。
	MiddlewareTimeout bool

	// MiddlewareRecovery 是否启用 Recovery 中间件。
	MiddlewareRecovery bool

	// MiddlewareValidation 是否启用 Validation 中间件。
	MiddlewareValidation bool
}

Config 定义 ginx Server 的全部配置项。

配置由调用方显式构造后传入 NewServer,ginx 不提供 DefaultConfig()。 所有校验在 Validate() 中集中进行,失败返回简体中文错误消息。

func (*Config) Validate

func (c *Config) Validate() error

Validate 对 Config 进行完整性校验,失败返回简体中文错误消息。

校验规则:

  • TLSCertFile 不能为空,文件必须存在且为普通文件
  • TLSKeyFile 不能为空,文件必须存在且为普通文件
  • 证书和私钥能够成功配对(tls.LoadX509KeyPair 成功)
  • 所有超时参数不能为负数
  • LogLevel 为空默认 "info",否则必须为有效级别
  • HealthPath 为空默认 "/health"

type Field

type Field struct {
	Key   string
	Value any
}

Field 表示一条结构化的日志字段。

func AnyField

func AnyField(key string, val any) Field

AnyField 创建一个任意类型的日志字段。

func DurationField

func DurationField(key string, val time.Duration) Field

DurationField 创建一个时间间隔类型的日志字段。

func ErrorField

func ErrorField(err error) Field

ErrorField 创建一个错误类型的日志字段,Key 固定为 "error"。

func IntField

func IntField(key string, val int) Field

IntField 创建一个整数类型的日志字段。

func StringField

func StringField(key, val string) Field

StringField 创建一个字符串类型的日志字段。

type HandlerFunc

type HandlerFunc = gin.HandlerFunc

HandlerFunc 是 gin.HandlerFunc 的类型别名。

这是 ginx 暴露的唯一 Gin 类型,调用方无需直接导入 Gin。

type Logger

type Logger interface {
	// Debug 记录调试级别日志。
	Debug(ctx context.Context, msg string, fields ...Field)

	// Info 记录信息级别日志。
	Info(ctx context.Context, msg string, fields ...Field)

	// Warn 记录警告级别日志。
	Warn(ctx context.Context, msg string, fields ...Field)

	// Error 记录错误级别日志。
	Error(ctx context.Context, msg string, fields ...Field)

	// Fatal 记录致命级别日志。
	Fatal(ctx context.Context, msg string, fields ...Field)
}

Logger 定义 ginx 的日志接口。

调用方通过实现此接口注入自定义日志组件(如 Zap、Zerolog)。 默认使用 NoopLogger,所有方法为空实现,编译器内联,零分配。

type MiddlewareType

type MiddlewareType string

MiddlewareType 标识内置中间件的类型。

const (
	// MiddlewareRequestID 请求 ID 生成中间件。
	MiddlewareRequestID MiddlewareType = "request_id"

	// MiddlewareCORS 跨域处理中间件。
	MiddlewareCORS MiddlewareType = "cors"

	// MiddlewareTimeout 请求超时中间件。
	MiddlewareTimeout MiddlewareType = "timeout"

	// MiddlewareRecovery Panic 捕获中间件。
	MiddlewareRecovery MiddlewareType = "recovery"

	// MiddlewareValidation 请求参数校验中间件。
	MiddlewareValidation MiddlewareType = "validation"

	// MiddlewareRateLimit IP 令牌桶限流中间件。
	MiddlewareRateLimit MiddlewareType = "rate_limit"
)

type NoopLogger

type NoopLogger struct{}

NoopLogger 是 Logger 接口的空实现,所有方法不执行任何操作。

编译器会将 NoopLogger 的方法内联,确保零分配开销。 当调用方未注入自定义 Logger 时,Server 默认使用此实现。

func (NoopLogger) Debug

func (n NoopLogger) Debug(_ context.Context, _ string, _ ...Field)

Debug 空实现。

func (NoopLogger) Error

func (n NoopLogger) Error(_ context.Context, _ string, _ ...Field)

Error 空实现。

func (NoopLogger) Fatal

func (n NoopLogger) Fatal(_ context.Context, _ string, _ ...Field)

Fatal 空实现。

func (NoopLogger) Info

func (n NoopLogger) Info(_ context.Context, _ string, _ ...Field)

Info 空实现。

func (NoopLogger) Warn

func (n NoopLogger) Warn(_ context.Context, _ string, _ ...Field)

Warn 空实现。

type RateLimitOptions

type RateLimitOptions struct {
	// QPS 每 IP 每秒允许的请求数(必填,> 0)。
	QPS int

	// Window 限流窗口时长(必填,> 0)。
	Window time.Duration

	// Whitelist 白名单 IP/CIDR 列表(可选)。
	Whitelist []string

	// CleanupInterval 过期桶清理间隔(可选,0 = 默认 5 分钟)。
	CleanupInterval time.Duration
}

RateLimitOptions 定义 IP 限流中间件的配置参数。

type Route

type Route struct {
	// Method HTTP 方法,如 GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS。
	Method string

	// Path 路由路径,如 "/api/users/:id"。
	Path string

	// Handler 路由处理器。
	Handler HandlerFunc

	// Middleware 路由专属中间件(可选),仅对当前路由生效。
	Middleware []HandlerFunc
}

Route 定义一条 HTTP 路由。

type RouteGroup

type RouteGroup struct {
	// contains filtered or unexported fields
}

RouteGroup 路由分组,支持嵌套分组和分组级中间件。

RouteGroup 仅缓冲注册,Start() 时一次性挂载到 Gin 引擎。

func (*RouteGroup) DELETE

func (rg *RouteGroup) DELETE(path string, handler HandlerFunc, mw ...HandlerFunc)

DELETE 注册一条 DELETE 方法路由。

func (*RouteGroup) GET

func (rg *RouteGroup) GET(path string, handler HandlerFunc, mw ...HandlerFunc)

GET 注册一条 GET 方法路由。

func (*RouteGroup) Group

func (rg *RouteGroup) Group(relativePath string) *RouteGroup

Group 创建一个子分组,子分组继承父分组的 prefix 和中间件。

func (*RouteGroup) PATCH

func (rg *RouteGroup) PATCH(path string, handler HandlerFunc, mw ...HandlerFunc)

PATCH 注册一条 PATCH 方法路由。

func (*RouteGroup) POST

func (rg *RouteGroup) POST(path string, handler HandlerFunc, mw ...HandlerFunc)

POST 注册一条 POST 方法路由。

func (*RouteGroup) PUT

func (rg *RouteGroup) PUT(path string, handler HandlerFunc, mw ...HandlerFunc)

PUT 注册一条 PUT 方法路由。

func (*RouteGroup) Use

func (rg *RouteGroup) Use(middleware ...HandlerFunc)

Use 向当前分组追加中间件,影响该分组内所有已注册和后续注册的路由。

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server 是 ginx 的核心类型,封装 Gin 引擎并提供工业级 HTTPS Server 能力。

通过链式 API 进行配置,调用 Start() 启动服务,Stop(ctx) 优雅关闭。 v0.2.0 起支持 HTTP/2、HTTP/3 (QUIC) 和 Unix Socket 多通道同时监听。

func NewServer

func NewServer(cfg Config) *Server

NewServer 创建一个新的 ginx Server 实例。

cfg 由调用方显式构造,ginx 不提供默认配置。

func (*Server) DisableMiddleware

func (s *Server) DisableMiddleware(mt ...MiddlewareType) *Server

DisableMiddleware 禁用指定类型的内置中间件。

func (*Server) DisableRateLimit

func (s *Server) DisableRateLimit() *Server

DisableRateLimit 禁用 IP 限流中间件。

func (*Server) EnableMiddleware

func (s *Server) EnableMiddleware(mt ...MiddlewareType) *Server

EnableMiddleware 重新启用指定类型的内置中间件(RateLimit 除外)。

func (*Server) EnableRateLimit

func (s *Server) EnableRateLimit(opts RateLimitOptions) *Server

EnableRateLimit 启用 IP 限流中间件。

func (*Server) EnableSPA

func (s *Server) EnableSPA(filesys http.FileSystem, indexPath string) *Server

EnableSPA 启用 SPA 回退模式。

启用后,未匹配到任何路由的 GET/HEAD 请求将返回指定的 index 文件, 而非标准的 JSON 404 响应。非 GET/HEAD 请求仍返回标准 JSON 错误。

indexPath 是相对于 fs 的文件路径,通常为 "index.html"。 重复调用会覆盖之前的配置。

使用示例:

s.ServeStaticFS("/", http.FS(distFS))
s.EnableSPA(http.FS(distFS), "index.html")

func (*Server) ListenerAddr

func (s *Server) ListenerAddr() string

ListenerAddr 返回第一个 Listener 的监听地址,线程安全。

当使用 port 0 动态分配端口时,可通过此方法获取实际监听端口。 若尚未创建任何 Listener,返回空字符串。

func (*Server) OverrideMiddleware

func (s *Server) OverrideMiddleware(mt MiddlewareType, mw HandlerFunc) *Server

OverrideMiddleware 使用自定义 Handler 覆盖指定类型的内置中间件。

func (*Server) RegisterRoute

func (s *Server) RegisterRoute(r Route) *Server

RegisterRoute 注册单条路由。

func (*Server) RegisterRouteGroup

func (s *Server) RegisterRouteGroup(prefix string, fn func(*RouteGroup)) *Server

RegisterRouteGroup 注册路由分组。

fn 在 Start() 时被调用以展开分组内路由。

func (*Server) RegisterRoutes

func (s *Server) RegisterRoutes(routes []Route) *Server

RegisterRoutes 批量注册路由。

func (*Server) ServeStaticDir

func (s *Server) ServeStaticDir(prefix, root string) *Server

ServeStaticDir 从本地目录提供静态文件。

等价于 gin.Engine.Static(prefix, root)。 root 必须是本地文件系统上已存在的目录。

func (*Server) ServeStaticFS

func (s *Server) ServeStaticFS(prefix string, filesys http.FileSystem) *Server

ServeStaticFS 从 http.FileSystem 提供静态文件。

配合 Go embed 包使用可将前端资源嵌入二进制:

//go:embed all:frontend/dist
var spaAssets embed.FS
distFS, _ := fs.Sub(spaAssets, "frontend/dist")
s.ServeStaticFS("/", http.FS(distFS))

等价于 gin.Engine.StaticFS(prefix, fs)。

func (*Server) Start

func (s *Server) Start() error

Start 启动 HTTPS 服务。

执行配置校验、中间件加载、路由注册、各通道监听器创建和启动, 调用后阻塞直到收到关闭信号或发生错误。

func (*Server) Stop

func (s *Server) Stop(ctx context.Context) error

Stop 优雅关闭 HTTPS 服务。

使用 sync.Once 保护,重复调用安全。 关闭所有 HTTP Server 和 Listener。

func (*Server) UseGlobalMiddleware

func (s *Server) UseGlobalMiddleware(mw ...HandlerFunc) *Server

UseGlobalMiddleware 追加外部全局中间件。

func (*Server) UseHttp2Listen

func (s *Server) UseHttp2Listen(addr string) *Server

UseHttp2Listen 启用 HTTP/2 TLS 监听(含 HTTP/1.1 兼容)。

addr 格式如 ":443" 或 "0.0.0.0:8888"。

func (*Server) UseHttp3Listen

func (s *Server) UseHttp3Listen(addr string) *Server

UseHttp3Listen 启用 HTTP/3 QUIC 监听。

addr 独立指定,与 HTTP/2 无关。格式如 ":443" 或 "127.0.0.1:9900"。

func (*Server) UseUnixSocketListen

func (s *Server) UseUnixSocketListen(path string, perm os.FileMode) *Server

UseUnixSocketListen 启用 Unix Socket 监听。

perm 为 Socket 文件权限,为 0 则默认 0660。

func (*Server) WithLogger

func (s *Server) WithLogger(l Logger) *Server

WithLogger 注入自定义 Logger 实现。

type StandardizedResponse

type StandardizedResponse struct {
	Code      int    `json:"code"`
	Msg       string `json:"msg"`
	Data      any    `json:"data,omitempty"`
	RequestID string `json:"requestId"`
	Timestamp int64  `json:"timestamp"`
}

StandardizedResponse 是 ginx 统一的标准 JSON 响应体。

所有正常响应和异常兜底(404/405/429/500/503)均使用此结构。 msg 字段使用简体中文。

Directories

Path Synopsis
Package middleware 提供 ginx 内置的 HTTP 中间件实现。
Package middleware 提供 ginx 内置的 HTTP 中间件实现。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL