mengstack-website/guide/quality.md
MengStack Dev fca3326e34 docs: 官网文档全面更新 — M2-M8 指南 + API 参考 + v0.2.0 更新日志
- 更新 changelog.md: v0.2.0 记录 M2-M8 全部完成,路线图更新
- 新增 5 篇指南: RBAC、组织管理、审计日志、通知模块、质量横切
- 新增 5 篇 API 文档: RBAC(11)、Org(5)、Audit(1)、Settings(7)、Notification(7)
- 更新 api/overview.md: 完整 37 端点列表
- 更新 config.ts: 侧边栏分组 + 11 页 SEO 元数据
2026-10-03 01:55:55 +08:00

3.6 KiB
Raw Blame History

title
质量横切 | 安全基线、限流、日志与优雅停机 - MengStack官方文档

质量横切

M8 为框架添加了生产级质量基线,覆盖安全、限流、日志、容错和测试基础设施。

中间件链

所有请求经过以下中间件链(按顺序):

RequestID → RequestLogger → SecurityHeaders → CORS → RateLimit → BodyLimit → Recovery

IP 限流

基于内存的 IP 限流中间件,自动清理过期记录:

// 每个 IP 每分钟最多 100 次请求
r.Use(middleware.RateLimit(100, time.Minute))
特性 说明
限流维度 客户端 IP
存储方式 内存 map + sync.Mutex
自动清理 后台 goroutine 每分钟清理过期记录
超限响应 HTTP 429 + RATE_LIMITED 错误码

::: warning 内存限流适合单机部署。多实例部署建议替换为 Redis 限流。 :::

安全响应头

自动为所有响应添加安全头:

Header 值 作用
X-Content-Type-Options nosniff 防止 MIME 类型嗅探
X-Frame-Options DENY 防止点击劫持
X-XSS-Protection 1; mode=block 浏览器 XSS 过滤
Referrer-Policy strict-origin-when-cross-origin 控制 Referer 泄露
Content-Security-Policy default-src 'self' 限制资源加载来源

请求体限制

限制请求体最大为 10MB,防止大文件攻击:

r.Use(middleware.BodyLimit(10 << 20))  // 10 MB
  • 先检查 Content-Length header,超限直接返回 413
  • 再通过 http.MaxBytesReader 限制实际读取大小

结构化请求日志

使用 Zap 替代 fmt,输出结构化 JSON 日志:

{
  "level": "info",
  "msg": "request",
  "status": 200,
  "method": "GET",
  "path": "/api/v1/profile",
  "query": "",
  "ip": "192.168.1.100",
  "user-agent": "Mozilla/5.0",
  "latency_ms": 12,
  "trace_id": "req-abc-123"
}

日志级别按状态码自动选择:

状态码范围 日志级别
< 400 INFO
400-499 WARN
>= 500 ERROR

自定义 Recovery

替代 gin.Recovery(),panic 信息通过 Zap 记录而非 stdout:

r.Use(middleware.Recovery(log))

记录的字段:panic 内容、stack trace、请求方法、路径、trace_id。

优雅停机

应用收到终止信号后,等待最多 10 秒处理完进行中的请求:

// app.go
OnStop: func(ctx context.Context) error {
    shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    return srv.Shutdown(shutdownCtx)
}

测试基础设施

testutil 包

import "mengstack/internal/kernel/testutil"

func TestSomething(t *testing.T) {
    log := testutil.TestLogger(t)  // 测试专用 Zap logger
    cfg := testutil.TestConfig()   // 最小化测试配置
}

中间件测试

内置 11 个单元测试覆盖所有中间件:

go test ./internal/app/middleware/ -v
测试 覆盖场景
TestRequestID_GeneratesNew 无 trace_id 时自动生成
TestRequestID_PreservesExisting 已有 trace_id 时保留
TestSecurityHeaders 5 个安全头全部设置
TestRateLimit_AllowsWithinLimit 限额内请求正常通过
TestRateLimit_BlocksOverLimit 超限额返回 429
TestRequestLogger_DoesNotPanic 日志中间件不 panic
TestRecovery_HandlesPanic 捕获 panic 并记录
TestBodyLimit_RejectsLargeBody 超大 body 返回 413
TestBodyLimit_AllowsSmallBody 正常 body 通过

数据库时区

PostgreSQL DSN 默认携带 TimeZone=Asia/Shanghai,确保时间字段按中国时区存储和返回。