返回首页

使用 Go 无 CGO 和框架的无头 CMS

无外部依赖的 Go 极简无头 CMS,用于着陆页。使用 modernc/sqlite、net/http、Bitrix24 的通道。完整安全性和零配置启动。

使用 Go 创建无头 CMS:20 MB 无依赖
Advertisement 728x90

纯Go实现的极简无头CMS:架构与实战

关键选择是使用 modernc.org/sqlite 而不是 mattn/go-sqlite3。这是一个纯Go编写的SQLite移植版本,兼容 database/sql API,无需C编译器。

import (
    "database/sql"
    _ "modernc.org/sqlite"
)

func Open(path string) (*sql.DB, error) {
    db, err := sql.Open("sqlite", path)
    if err != nil {
        return nil, err
    }

    // WAL模式支持并发读写
    pragmas := []string{
        "PRAGMA journal_mode=WAL",
        "PRAGMA busy_timeout=5000",
        "PRAGMA foreign_keys=ON",
        "PRAGMA synchronous=NORMAL",
    }
    for _, p := range pragmas {
        if _, err := db.Exec(p); err != nil {
            return nil, fmt.Errorf("pragma %q: %w", p, err)
        }
    }
    return db, nil
}

WAL模式允许在写入时并行读取——这对同时运行API和管理后台至关重要。

基于 net/http 的路由与中间件

放弃Gin/Echo/Chi,改用 http.ServeMux 可减少依赖,简化调试流程:

Google AdInline article slot
mux := http.NewServeMux()

// 公共API
mux.Handle("/api/leads", rateLimiter(http.HandlerFunc(h.CreateLead)))
mux.Handle("/api/news", http.HandlerFunc(h.ListNews))

// 管理面板
mux.Handle("/admin/", authMiddleware(sessionStore, adminHandler))

中间件链:logger → rateLimiter → auth → csrfCheck → handler。每个组件都是独立、可测试的函数。

通过Go通道实现异步集成(以Bitrix24为例)

客户线索提交至CRM采用异步方式,借助Go通道与工作池完成,无需Redis或Celery:

type Worker struct {
    db      *sql.DB
    queue   chan Job
    webhook string
    wg      sync.WaitGroup
}

func NewWorker(db *sql.DB, webhook string, poolSize int) *Worker {
    w := &Worker{
        db:      db,
        queue:   make(chan Job, 100),
        webhook: webhook,
    }
    for i := 0; i < poolSize; i++ {
        w.wg.Add(1)
        go w.process()
    }
    return w
}

func (w *Worker) Enqueue(job Job) {
    select {
    case w.queue <- job:
    default:
        log.Printf("bitrix queue full, lead %d will be retried manually", job.LeadID)
    }
}

队列缓冲区为100个任务,支持30秒超时的优雅关闭。

Google AdInline article slot

使用HMAC-SHA256实现CSRF防护

管理表单结合HTMX,通过同步令牌进行保护:

func generateCSRFToken(sessionID, secret string) string {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(sessionID))
    return hex.EncodeToString(mac.Sum(nil))
}

func validateCSRFToken(r *http.Request, sessionID, secret string) bool {
    token := r.FormValue("csrf_token")
    if token == "" {
        token = r.Header.Get("X-CSRF-Token")
    }
    expected := generateCSRFToken(sessionID, secret)
    return hmac.Equal([]byte(token), []byte(expected))
}

令牌嵌入表单与HTMX请求头中,hmac.Equal 防止时间差攻击。

内存级限流机制

公共API对每个IP限制每分钟最多10次请求,无需外部存储:

Google AdInline article slot
type IPLimiter struct {
    visitors sync.Map
    mu       sync.Mutex
}

type entry struct {
    count   int
    resetAt time.Time
}

func (l *IPLimiter) Allow(ip string) bool {
    now := time.Now()
    val, _ := l.visitors.LoadOrStore(ip, &entry{resetAt: now.Add(time.Minute)})
    e := val.(*entry)

    l.mu.Lock()
    defer l.mu.Unlock()

    if now.After(e.resetAt) {
        e.count = 0
        e.resetAt = now.Add(time.Minute)
    }
    if e.count >= 10 {
        return false
    }
    e.count++
    return true
}

使用 sync.Map,每5分钟自动清理过期记录。

首次运行无需配置

服务器启动时自动初始化数据库,生成管理员密码并输出到控制台。可通过命令行参数或环境变量配置:

  • ./cms —— 使用默认值(端口8080,数据库路径=./cms.db)
  • CMS_PORT=8080 CMS_DB_PATH=./data.db ./cms

安全措施

| 威胁 | 缓解方案 |

|------|----------|

| SQL注入 | 参数化查询 |

| XSS | html/template 自动转义 |

| CSRF | HMAC令牌 |

| 暴力破解 | 限流至10次/分钟 |

| 路径遍历 | http.FileServer 限制在沙箱目录 |

核心亮点:

  • 二进制文件约20MB,静态资源通过 embed.FS 内嵌,运行时零依赖
  • WAL模式的SQLite支持高并发无锁访问
  • 使用Go通道替代Redis/Celery队列
  • HMAC CSRF + html/template 构建强安全体系
  • CGO_ENABLED=0 支持从Windows跨平台编译至Linux

— Editorial Team

Advertisement 728x90

继续阅读