Serve admin console at root path
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+5
-5
@@ -1,12 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/admin/favicon.svg" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>admin</title>
|
||||
<script type="module" crossorigin src="/admin/assets/index-DmUsbLpt.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/admin/assets/index-BQA5NViF.css">
|
||||
<title>肉垫计划 · 管理端</title>
|
||||
<script type="module" crossorigin src="/assets/index-COwxdvZQ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BQA5NViF.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
//go:embed all:dist
|
||||
var distFS embed.FS
|
||||
|
||||
// Register 把内嵌的后台 SPA 挂到 /admin 下,index.html 做 SPA fallback
|
||||
// Register 把内嵌的后台 SPA 挂到根路径,保留 /api 给业务接口。
|
||||
func Register(r *gin.Engine) {
|
||||
sub, err := fs.Sub(distFS, "dist")
|
||||
if err != nil {
|
||||
@@ -21,9 +21,7 @@ func Register(r *gin.Engine) {
|
||||
fileServer := http.FileServer(http.FS(sub))
|
||||
|
||||
handler := func(c *gin.Context) {
|
||||
// 去掉前缀 /admin,交给内嵌文件服务器
|
||||
reqPath := strings.TrimPrefix(c.Request.URL.Path, "/admin")
|
||||
reqPath = strings.TrimPrefix(reqPath, "/")
|
||||
reqPath := strings.TrimPrefix(c.Request.URL.Path, "/")
|
||||
|
||||
// 若请求的是真实存在的静态资源,直出;否则回退 index.html(前端路由)
|
||||
if reqPath != "" {
|
||||
@@ -43,6 +41,12 @@ func Register(r *gin.Engine) {
|
||||
c.Data(http.StatusOK, "text/html; charset=utf-8", data)
|
||||
}
|
||||
|
||||
r.GET("/admin", func(c *gin.Context) { c.Redirect(http.StatusFound, "/admin/") })
|
||||
r.GET("/admin/*filepath", handler)
|
||||
r.GET("/", handler)
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
if c.Request.Method != http.MethodGet || strings.HasPrefix(c.Request.URL.Path, "/api/") || c.Request.URL.Path == "/api" || strings.HasPrefix(c.Request.URL.Path, "/assets/") {
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
handler(c)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sundynix/pets-be/internal/config"
|
||||
"github.com/sundynix/pets-be/internal/httpapi"
|
||||
)
|
||||
|
||||
func TestAdminAtRootAndAPIRoutes(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
r := gin.New()
|
||||
httpapi.New(nil, nil, &config.Config{}).Register(r)
|
||||
Register(r)
|
||||
|
||||
for _, tc := range []struct {
|
||||
path string
|
||||
status int
|
||||
body string
|
||||
}{
|
||||
{path: "/", status: http.StatusOK, body: "<div id=\"root\"></div>"},
|
||||
{path: "/api/ping", status: http.StatusOK, body: "pong"},
|
||||
{path: "/api/missing", status: http.StatusNotFound},
|
||||
{path: "/assets/missing.js", status: http.StatusNotFound},
|
||||
} {
|
||||
recorder := httptest.NewRecorder()
|
||||
r.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, tc.path, nil))
|
||||
if recorder.Code != tc.status || (tc.body != "" && !strings.Contains(recorder.Body.String(), tc.body)) {
|
||||
t.Errorf("GET %s: got %d %q, want %d containing %q", tc.path, recorder.Code, recorder.Body.String(), tc.status, tc.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user