package resources import ( "embed" "errors" "fmt" "github.com/gin-gonic/gin" "io/fs" "net/http" "os" "path" "path/filepath" "strings" ) //go:embed assets/index.html var index []byte //go:embed assets/assets var Static embed.FS //go:embed images var Images embed.FS //go:embed assets/favicon.ico var ICO embed.FS //go:embed template/defaultAvatar.jpg var DefaultAvatar embed.FS //go:embed app/index.html var app []byte //go:embed app var APP embed.FS const ( apiBase = "/api/v1" adminApi = "/admin-api/" assetsProxy = "assets" ) func HtmlRouteHandler() gin.HandlerFunc { return func(context *gin.Context) { var uri = context.Request.URL.Path var ext = path.Ext(uri) if find := strings.Contains(uri, apiBase); find { return } else if find = ext == ".txt"; find { //打开文件 file, err := os.Open("." + uri) defer file.Close() if err != nil { fmt.Println("打开文件错误", err) } context.File("." + uri) context.Abort() return } accept := context.Request.Header.Get("Accept") if strings.Contains(accept, "text/html") { writeIndex(context) } } } func writeIndex(context *gin.Context) { agent := context.Request.Header.Get("User-Agent") if strings.Contains(strings.ToLower(agent), "mobile") { context.Redirect(http.StatusFound, "/app") return } context.Writer.WriteHeader(200) context.Writer.Header().Add("Accept", "text/html") _, _ = context.Writer.Write(index) context.Writer.Flush() context.Abort() } type Resource struct { fs embed.FS path string } func NewResource() *Resource { return &Resource{ fs: Static, path: "assets", } } func NewAppResource() *Resource { return &Resource{ fs: APP, path: "app/", } } func NewImagesResource() *Resource { return &Resource{ fs: Images, path: "images/", } } func (r *Resource) Open(name string) (fs.File, error) { if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) { return nil, errors.New("http: invalid character in file path") } fullName := r.getFullName(name) file, err := r.fs.Open(fullName) return file, err } func (r *Resource) getFullName(name string) string { if r.path == "assets" { return r.path + "/assets/" + name } return r.path + name } func InitResource(engine *gin.Engine) { resourceRouter(engine) engine.StaticFS("/assets", http.FS(NewResource())) engine.StaticFS("/app", http.FS(NewAppResource())) engine.StaticFS("/images", http.FS(NewImagesResource())) } type HtmlHandler struct{} func NewHtmlHandler() *HtmlHandler { return &HtmlHandler{} } // RedirectIndex 404 重定向 func (h *HtmlHandler) RedirectIndex(context *gin.Context) { var uri = context.Request.URL.Path if strings.Contains(uri, adminApi) { context.Abort() return } accept := context.Request.Header.Get("Accept") if strings.Contains(accept, "text/html") { writeIndex(context) } } func (h *HtmlHandler) Index(context *gin.Context) { writeIndex(context) } func (h *HtmlHandler) App(context *gin.Context) { context.Writer.WriteHeader(200) context.Writer.Header().Add("Accept", "text/html") _, _ = context.Writer.Write(app) context.Writer.Flush() context.Abort() } // resourceRouter 静态资源配置 func resourceRouter(engine *gin.Engine) { html := NewHtmlHandler() group := engine.Group("/") { group.GET("", html.Index) group.GET("/app", html.App) group.GET("/defaultAvatar", func(context *gin.Context) { context.Request.URL.Path = "template/defaultAvatar.jpg" staticServer := http.FileServer(http.FS(DefaultAvatar)) staticServer.ServeHTTP(context.Writer, context.Request) context.Abort() }) group.GET("favicon.ico", func(context *gin.Context) { context.Request.URL.Path = assetsProxy + context.Request.URL.Path staticServer := http.FileServer(http.FS(ICO)) staticServer.ServeHTTP(context.Writer, context.Request) context.Abort() }) } // 解决刷新 404 问题 engine.NoRoute(html.RedirectIndex) }