优化小程序部分

This commit is contained in:
hero920103 committed 2026-10-31 19:17:37 +08:00
1 parent 727319a6eb
commit d4e89788c5
46 files changed
+4906 -63

No files matched your search

+117
View File
@@ -0,0 +1,117 @@
package routers
import (
"log"
"net/http"
"os"
"path/filepath"
"strings"
"server/pkg/verifyfiles"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/server/web/context"
)
// appRoot 定位服务根目录(conf/app.conf 所在目录的上一级)。
//
// beego 找配置的顺序是:当前工作目录 → 可执行文件所在目录。
// 这里沿用同样的顺序,保证不管是用 `go run main.go`(systemd 的 WorkingDirectory)
// 还是编译后的二进制、不管从哪个目录启动,验证文件目录都稳定落在服务根目录下,
// 不会出现「换个目录启动就找不到验证文件」的情况。
//
// 线上即 /www/wwwroot/api.yunzer.cn(conf/app.conf 在 /www/wwwroot/api.yunzer.cn/conf/)。
func appRoot() string {
candidates := make([]string, 0, 2)
if wd, err := os.Getwd(); err == nil {
candidates = append(candidates, wd)
}
if beego.AppPath != "" {
candidates = append(candidates, beego.AppPath)
}
return appRootFrom(candidates)
}
// appRootFrom 在候选目录里找第一个含 conf/app.conf 的目录(即服务根目录)。
func appRootFrom(candidates []string) string {
for _, base := range candidates {
if base == "" {
continue
}
if _, err := os.Stat(filepath.Join(base, "conf", "app.conf")); err == nil {
return base
}
}
return ""
}
// RegisterVerifyFiles 让 Go 直接吐「根路径站点验证文件」。
//
// 背景:nginx 对所有域名都是全量反代给 Go(location / → proxy_pass),
// Go 不认识的路径一律回 beego 404 页,于是这些文件根本访问不到:
// - 备案 / 域名所有权验证:1XXl8fPHr9.txt(阿里云、腾讯云)
// - 搜索引擎站点验证:googleXXXX.html、msXXXXXXXX.txt、Bing 的 .xml
// - 第三方平台域名校验:各平台给的 .txt / .html
//
// 这些文件名每次都不同(随机串),逐个注册路由不现实;改 nginx 又会因为
// 宝塔重生成 vhost 被冲掉(同 routers/spa.go 里遇到的问题)。
// 所以由 Go 统一托管:只要把验证文件丢进 verify 目录,
// https://api.yunzer.cn/1XXl8fPHr9.txt 就能直接取到。
//
// 规则:
// - 只处理 GET / HEAD;
// - 只认「根路径下的单段文件名」,如 /1XXl8fPHr9.txt;
// - 文件名过白名单正则,扩展名在允许列表内(默认 .txt/.html/.htm);
// - 文件必须真实存在于验证目录,否则放行给正常路由(最终仍是 beego 404)。
//
// 验证文件目录由 app.conf 的 verify_dir 指定(默认相对进程工作目录的 verify,
// 即线上服务目录 /www/wwwroot/api.yunzer.cn/verify);verify_hosts 可限定生效域名,
// 留空表示所有走本服务的域名都生效(备案常常同时要过 api.yunzer.cn 与官网主域名)。
func RegisterVerifyFiles(dir string, exts string, hosts ...string) {
dir = strings.TrimSpace(dir)
if dir == "-" {
// 显式关闭
return
}
if dir == "" {
// 默认:服务根目录下的 verify/(app.conf 所在目录的上一级)
dir = filepath.Join(appRoot(), verifyfiles.DefaultDir)
}
resolver, err := verifyfiles.New(verifyfiles.Config{
Dir: dir,
Exts: exts,
Hosts: strings.Join(hosts, ","),
})
if err != nil {
log.Printf("[verify] 根路径验证文件功能未启用: %v", err)
return
}
if resolver == nil {
// dir = "-":显式关闭
return
}
// 目录不存在就建一个,方便直接往里丢验证文件
if err := os.MkdirAll(resolver.Dir(), 0o755); err != nil {
log.Printf("[verify] 创建验证文件目录失败: %v", err)
}
beego.InsertFilter("*", beego.BeforeStatic, func(ctx *context.Context) {
if ctx.Request.Method != http.MethodGet && ctx.Request.Method != http.MethodHead {
return
}
if !resolver.AllowHost(ctx.Request.Host) {
return
}
full, ok := resolver.Resolve(ctx.Request.URL.Path)
if !ok {
return
}
// 文件内容不变,但可能被替换(换 token、换文件名),短缓存即可
ctx.Output.Header("Cache-Control", "public, max-age=300")
http.ServeFile(ctx.ResponseWriter, ctx.Request, full)
})
log.Printf("[verify] 根路径验证文件目录: %s,允许扩展名: %v", resolver.Dir(), resolver.Exts())
}