fix(web): 静态资源内嵌二进制,修复 install.sh 部署后 /static 404 导致写邮件页无编辑器

- 线上经 install.sh 部署时只复制二进制 + templates,internal/web/static
  未被复制,/static/vendor/quill/* 全部 404,Quill 加载失败正文不可输入
- 改为 go:embed 把 Quill css/js 编译进二进制,engine.StaticFS 提供,
  运行期不再依赖部署目录/工作目录,杜绝同类部署遗漏
- 已验证:移除磁盘 static 目录后静态资源仍可正常提供
This commit is contained in:
2026-08-20 01:46:43 +08:00
parent 2f7f322b62
commit 87a85ef7ca
2 changed files with 27 additions and 3 deletions
+14 -3
View File
@@ -4,13 +4,14 @@ import (
"encoding/json"
"fmt"
"html/template"
"io/fs"
"math"
"net"
"net/http"
"net/url"
"os"
"strconv"
"path/filepath"
"strconv"
"strings"
"time"
"unicode/utf8"
@@ -56,6 +57,8 @@ type WebServer struct {
caddyDataDir string
outbound *outbound.Manager
hub *connhub.Hub
// staticFS 内嵌的静态资源(/static 路由),二进制自包含
staticFS http.FileSystem
// pusher 邮件状态变化推送(IMAP 客户端实时同步),可空
pusher imap_server.Pusher
}
@@ -291,6 +294,12 @@ func NewWebServer(cfg config.WebConfig, stores *store.Stores, attStorage *storag
template.Must(tmpl.ParseGlob("internal/web/templates/admin/*.html"))
engine.SetHTMLTemplate(tmpl)
// 内嵌静态资源根目录(/static 路由数据源)
staticSub, err := fs.Sub(staticFS, "static")
if err != nil {
return nil, fmt.Errorf("加载内嵌静态资源失败: %w", err)
}
ws := &WebServer{
engine: engine,
stores: stores,
@@ -302,6 +311,7 @@ func NewWebServer(cfg config.WebConfig, stores *store.Stores, attStorage *storag
caddyDataDir: caddyCfg.DataDir,
outbound: ob,
hub: hub,
staticFS: http.FS(staticSub),
pusher: pusher,
}
@@ -321,8 +331,9 @@ func (ws *WebServer) registerRoutes() {
ws.engine.Use(middleware.SecurityHeaders())
// 静态资源(本地化的 Quill 编辑器等第三方前端库)。
// 同源加载以满足 CSP script-src/style-src 'self'且服务器离线可用。
ws.engine.Static("/static", "internal/web/static")
// 内嵌于二进制:同源加载以满足 CSP script-src/style-src 'self'
// 且不依赖部署目录(install.sh 只复制二进制 + templates)。
ws.engine.StaticFS("/static", ws.staticFS)
// Public routes (no auth required)
ws.engine.GET("/login", authHandler.ShowLogin)
+13
View File
@@ -0,0 +1,13 @@
package web
// 静态资源内嵌进二进制:install.sh 只部署二进制 + templates
// 此前 internal/web/static/ 未被复制导致线上 /static 全部 404。
// go:embed 使前端资源自包含,不再依赖部署目录与工作目录。
import "embed"
// staticFS 包含 internal/web/static/ 下的全部静态资源
// (目前为本地化的 Quill 编辑器 css/js)。
//
//go:embed all:static
var staticFS embed.FS