新增支持前端嵌入

This commit is contained in:
2026-03-29 00:44:30 +08:00
parent 7a7d3aeaaa
commit 37acc7586b
3 changed files with 100 additions and 84 deletions

95
.gitignore vendored
View File

@@ -1,107 +1,38 @@
# 编译后的二进制文件 # 编译后的二进制文件
NetworkAuth NetworkAuth
NetworkAuth.exe NetworkAuth.exe
*.exe
*.exe~
*.dll
*.so
*.dylib
# Go 相关
*.test
*.out
go.work
go.work.sum
# 数据库文件 # 数据库文件
/database.db
/recharge.db
*.db *.db
*.sqlite *.db-shm
*.sqlite3 *.db-wal
# 配置文件 (包含敏感信息) # 配置文件 (包含敏感信息)
config.json config.json
config.yaml
config.yml
.env
.env.local
.env.production
# 日志文件 # 日志文件
logs/ logs/
*.log *.log
log/
# 临时文件 # 前端工程源码 (独立维护)
*.tmp frontend/
*.temp
*.swp # 升级/迁移临时缓存目录
*.swo 更新内容/
*~
node.txt
frontend
# IDE 和编辑器 # IDE 和编辑器
.vscode/settings.json .vscode/
.vscode/tasks.json !.vscode/launch.json
.vscode/extensions.json
# .vscode/launch.json # 保留调试配置
.idea/ .idea/
*.iml
*.ipr
*.iws
.project
.classpath
.settings/
*.sublime-project
*.sublime-workspace
# 操作系统 # 操作系统
.DS_Store .DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.ini
# 依赖和包管理 # 依赖和包管理
vendor/ vendor/
node_modules/ node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# 测试覆盖率 # 允许提交 Go embed 依赖的静态资源
coverage.txt # 屏蔽构建的前端产物
coverage.out public/dist/
*.cover public/dist/**
*.coverprofile
# 文档生成
docs/_build/
site/
# 备份文件
*.bak
*.backup
*.orig
# 压缩文件
*.zip
*.tar.gz
*.rar
*.7z
# 证书和密钥文件
*.pem
*.key
*.crt
*.p12
*.pfx
# 运行时文件
*.pid
*.sock

6
public/public.go Normal file
View File

@@ -0,0 +1,6 @@
package public
import "embed"
//go:embed all:dist
var Public embed.FS

View File

@@ -1,15 +1,94 @@
package server package server
import ( import (
"NetworkAuth/public"
"io"
"io/fs"
"net/http"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
// RegisterRoutes 聚合注册所有路由 // RegisterRoutes 聚合注册所有路由
func RegisterRoutes(r *gin.Engine) { func RegisterRoutes(r *gin.Engine) {
// 所有路由基于 /api // 1. 所有接口路由基于 /api
apiGroup := r.Group("/api") apiGroup := r.Group("/api")
RegisterInstallRoutes(apiGroup) RegisterInstallRoutes(apiGroup)
RegisterDefaultRoutes(apiGroup) RegisterDefaultRoutes(apiGroup)
RegisterAdminRoutes(apiGroup) RegisterAdminRoutes(apiGroup)
// 2. 注册前端静态资源及兜底路由
registerFrontendRoutes(r)
}
// registerFrontendRoutes 注册前端静态资源及兜底路由
func registerFrontendRoutes(r *gin.Engine) {
// 提取嵌入的 dist 目录
distFS, err := fs.Sub(public.Public, "dist")
if err != nil {
panic("Failed to initialize embedded static files: " + err.Error())
}
// 挂载静态资源目录 (如 assets)
// 根据 Vue 构建产物,通常有 /assets 或 /static 目录,这里我们直接把整个 distFS 映射到根路由
// 但为了避免与 /api 冲突,我们可以使用中间件和 NoRoute 来处理兜底
// 提供静态文件服务器
fileServer := http.FileServer(http.FS(distFS))
// 拦截并处理静态资源请求
r.Use(func(c *gin.Context) {
path := c.Request.URL.Path
// 如果是 API 请求,直接放行
if strings.HasPrefix(path, "/api") {
c.Next()
return
}
// 检查静态文件中是否存在该路径
// 移除开头的 "/"
cleanPath := strings.TrimPrefix(path, "/")
if cleanPath == "" {
cleanPath = "index.html"
}
// 尝试在嵌入的文件系统中查找文件
if _, err := fs.Stat(distFS, cleanPath); err == nil {
// 文件存在,交由 FileServer 处理
// 设置一些常见的缓存头
if strings.HasPrefix(path, "/static/") || strings.HasPrefix(path, "/assets/") {
c.Header("Cache-Control", "public, max-age=31536000")
}
fileServer.ServeHTTP(c.Writer, c.Request)
c.Abort()
return
}
c.Next()
})
// SPA 前端路由兜底 (处理 History 模式)
r.NoRoute(func(c *gin.Context) {
// 如果是 API 请求找不到路由,返回 404 JSON
if strings.HasPrefix(c.Request.URL.Path, "/api") {
c.JSON(http.StatusNotFound, gin.H{
"code": 404,
"msg": "API Not Found",
})
return
}
// 其他所有非 API 请求,都返回 index.html 交给前端 Vue Router 处理
c.Header("Content-Type", "text/html; charset=utf-8")
indexFile, err := distFS.Open("index.html")
if err != nil {
c.String(http.StatusInternalServerError, "Failed to load index.html")
return
}
defer indexFile.Close()
stat, _ := indexFile.Stat()
http.ServeContent(c.Writer, c.Request, "index.html", stat.ModTime(), indexFile.(io.ReadSeeker))
})
} }