官网/docs 嵌入新品牌图;sparkapi nginx 可在未重建镜像时提供 /favicon.ico 与页头 logo。 Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
1.8 KiB
Go
74 lines
1.8 KiB
Go
package httpx
|
|
|
|
import (
|
|
"io/fs"
|
|
"net/http"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func registerDocs(r *gin.Engine) {
|
|
r.GET("/openapi.yaml", func(c *gin.Context) {
|
|
c.Data(http.StatusOK, "application/yaml; charset=utf-8", openAPISpec)
|
|
})
|
|
serve := func(c *gin.Context) {
|
|
c.Data(http.StatusOK, "text/html; charset=utf-8", docsHTML)
|
|
}
|
|
r.GET("/docs", serve)
|
|
r.GET("/docs/enums", serve)
|
|
r.GET("/docs/errors", serve)
|
|
r.GET("/docs/", func(c *gin.Context) {
|
|
c.Redirect(http.StatusFound, "/docs")
|
|
})
|
|
|
|
staticRoot, err := fs.Sub(docsStatic, "docs/static")
|
|
if err != nil {
|
|
panic("docs static embed: " + err.Error())
|
|
}
|
|
serveStaticFile := func(name, contentType string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
b, err := fs.ReadFile(staticRoot, name)
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
c.Header("Cache-Control", "public, max-age=604800")
|
|
c.Data(http.StatusOK, contentType, b)
|
|
}
|
|
}
|
|
r.GET("/favicon.ico", serveStaticFile("favicon.ico", "image/x-icon"))
|
|
r.GET("/apple-touch-icon.png", serveStaticFile("apple-touch-icon.png", "image/png"))
|
|
r.GET("/docs/static/*filepath", func(c *gin.Context) {
|
|
rel := strings.TrimPrefix(c.Param("filepath"), "/")
|
|
rel = path.Clean("/" + rel)
|
|
rel = strings.TrimPrefix(rel, "/")
|
|
if rel == "" || strings.Contains(rel, "..") {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
b, err := fs.ReadFile(staticRoot, rel)
|
|
if err != nil {
|
|
c.Status(http.StatusNotFound)
|
|
return
|
|
}
|
|
ct := contentTypeFor(rel)
|
|
c.Header("Cache-Control", "public, max-age=604800")
|
|
c.Data(http.StatusOK, ct, b)
|
|
})
|
|
}
|
|
|
|
func contentTypeFor(name string) string {
|
|
switch strings.ToLower(path.Ext(name)) {
|
|
case ".png":
|
|
return "image/png"
|
|
case ".ico":
|
|
return "image/x-icon"
|
|
case ".svg":
|
|
return "image/svg+xml"
|
|
default:
|
|
return "application/octet-stream"
|
|
}
|
|
}
|