75 lines
2.6 KiB
Go
75 lines
2.6 KiB
Go
package router
|
||
|
||
import (
|
||
"fmt"
|
||
"net/url"
|
||
"time"
|
||
|
||
"fashionapi/internal/middleware"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// NewSSG 构建「仅供构建期使用的内部引擎」,并返回它。
|
||
//
|
||
// 与 New()(对外公开引擎,挂在 8090)的关键区别:
|
||
// 1. 不装载 CORS 中间件 —— SSG 是 server-to-server 的 node fetch 调用,CORS 是浏览器机制,用不上,反而减小攻击面;
|
||
// 2. 装载 SSGToken 中间件 —— 若配置了 SSG_TOKEN 则强制校验(防御纵深);
|
||
// 3. 只注册 /api/ssg/* 路由 —— 全量/全 ID 这类「构建专用」数据只在这里出现;
|
||
// 4. 该引擎由 main 监听在独立的内部端口(默认 8091),docker-compose 把它绑定到 127.0.0.1,
|
||
// nginx 也绝不反代,因此外部网络根本连不到,SSG 数据不会外泄。
|
||
//
|
||
// 这样即使有人从公网域名探测 /api/ssg/*,请求只会打到 nginx(80)或公开引擎(8090),
|
||
// 二者都没有该路由,自然 404 / 由 nginx 拦截,数据永不出口。
|
||
func NewSSG(opt Options) *gin.Engine {
|
||
r := gin.New()
|
||
r.Use(gin.Recovery())
|
||
r.Use(ssgLogger())
|
||
r.Use(middleware.SSGToken(opt.Config.Server.SSGToken))
|
||
|
||
ssg := r.Group("/api/v1/ssg")
|
||
{
|
||
ssg.GET("/brands/hot", opt.SSG.HotBrands) // 走秀页热门品牌(前 30,热度顺序)
|
||
ssg.GET("/index/runway", opt.SSG.IndexRunway) // 首页(/index/)runway 区块:多模块,当前含 hotBrand
|
||
ssg.GET("/street-snaps/popular", opt.SSG.StreetSnapPopular) // 首页热门街拍(按图片数前 20)
|
||
// 注:/street-snaps/ids(全部街拍编码 id 枚举)已移除——街拍详情页走 /item/[id] 按需 SSR,
|
||
// 无需构建期枚举 id。handler/service/repository 对应实现已一并删除。
|
||
}
|
||
|
||
return r
|
||
}
|
||
|
||
// ssgLogger 输出与公开引擎一致的请求日志,但会把 query string 里的 token 脱敏为 ***,
|
||
// 避免 SSG_TOKEN 在日志里明文泄露。
|
||
func ssgLogger() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
start := time.Now()
|
||
path := c.Request.URL.Path
|
||
rawQuery := c.Request.URL.RawQuery
|
||
if rawQuery != "" {
|
||
if q, err := url.ParseQuery(rawQuery); err == nil && q.Get("token") != "" {
|
||
q.Set("token", "***")
|
||
rawQuery = q.Encode()
|
||
}
|
||
}
|
||
|
||
c.Next()
|
||
|
||
latency := time.Since(start)
|
||
queryPart := ""
|
||
if rawQuery != "" {
|
||
queryPart = "?" + rawQuery
|
||
}
|
||
fmt.Fprintf(gin.DefaultWriter,
|
||
"[GIN] %s | %3d | %13v | %15s | %-7s %s%s\n",
|
||
time.Now().Format("2006/01/02 - 15:04:05"),
|
||
c.Writer.Status(),
|
||
latency,
|
||
c.ClientIP(),
|
||
c.Request.Method,
|
||
path,
|
||
queryPart,
|
||
)
|
||
}
|
||
}
|