Files
yunzerwebsiteallinone/go/routers/spa.go
T
2026-10-19 17:34:11 +08:00

83 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package routers
import (
"net/http"
"os"
"strings"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/server/web/context"
)
// RegisterPlatformSPA 让 Go 自己吐指定 hosts 的平台后台 SPA 静态资源,
// 替代 nginx 在对应 server 块里的
//
// location ~ ^/(platform|backend|auth|api|app)/ { proxy_pass http://127.0.0.1:8081; ... }
//
// 那段反代规则(曾因宝塔重生成 vhost 被冲掉而出现 "页面 404")。
//
// 规则:
// - 仅对 hosts 列表里的 host 生效;
// - 这些前缀直接放行交给 beego Router / Static 处理,不接管:
// /platform/、/backend/、/auth/、/api/、/app/ → 业务 API
// /uploads/、/themes/ → main.go SetStaticPath 注册的静态目录
// /.well-known/ → ACME 证书验证目录
// - 其余请求从 spaDir 直接 ServeFile;
// - 文件不存在时回 index.html(SPA hash 路由 fallback)。
//
// 调用方在 router.go init() 里读 app.conf 的 platform_spa_dir / platform_spa_hosts。
// spaDir 为空或 hosts 为空则视为关闭功能,行为不变。
func RegisterPlatformSPA(spaDir string, hosts ...string) {
spaDir = strings.TrimSpace(spaDir)
if spaDir == "" || len(hosts) == 0 {
return
}
hostSet := make(map[string]struct{}, len(hosts))
for _, h := range hosts {
h = strings.ToLower(strings.TrimSpace(h))
if h != "" {
hostSet[h] = struct{}{}
}
}
passThrough := []string{
"/platform/", "/backend/", "/auth/", "/api/", "/app/",
"/uploads/", "/themes/",
"/.well-known/",
}
beego.InsertFilter("*", beego.BeforeStatic, func(ctx *context.Context) {
host := strings.ToLower(ctx.Request.Host)
if i := strings.IndexByte(host, ':'); i > 0 {
host = host[:i]
}
if _, ok := hostSet[host]; !ok {
return
}
path := ctx.Request.URL.Path
for _, p := range passThrough {
if strings.HasPrefix(path, p) {
return
}
}
// 静态资源或入口
rel := path
if rel == "" || rel == "/" {
rel = "/index.html"
}
target := spaDir + rel
if f, err := os.Stat(target); err == nil && !f.IsDir() {
http.ServeFile(ctx.ResponseWriter, ctx.Request, target)
return
}
// SPA fallback:未知路径(hash 路由直接访问 /xxx/yyy)回 index.html。
// 标记一下,避免安全探针过滤器把「兜底返回首页」误判成敏感文件泄露。
ctx.Input.SetData("spa_fallback", true)
http.ServeFile(ctx.ResponseWriter, ctx.Request, spaDir+"/index.html")
})
}