feat(backend): 公开接口反爬轻量版——per-IP 日配额 + 列表收紧(todo #3)

DailyQuota 二级闸(单品 1000/日、店铺列表 300/日,0=关;出错放行不误伤);
店铺列表 page_size 上限 50→20(客户端固定传 20 无破坏);公开响应敏感字段
(cost/purchase_price/profit)零暴露回归测试。
明确不做:签名链接(QR 已印刷+UUIDv4 不可枚举)、滑块(杀零门槛分享)、登录墙。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-07-05 10:42:23 +08:00
parent 3c687e5e0b
commit 290054dc8c
5 changed files with 221 additions and 4 deletions
+6 -3
View File
@@ -59,9 +59,12 @@ func Setup(r *gin.Engine, db *gorm.DB) {
refreshIP := middleware.RateLimitByIP(middleware.PerMinute(rl.RefreshPerMin), rl.RefreshPerMin)
registerIP := middleware.RateLimitByIP(middleware.PerMinute(rl.RegisterPerMin), rl.RegisterPerMin)
errorsIP := middleware.RateLimitByIP(middleware.PerMinute(rl.ErrorsPerMin), rl.ErrorsPerMin)
// 日配额二级闸(同一 IP 自然日累计,反爬):单品 API 与 OG 页同一配额池
dqProduct := middleware.DailyQuota("product", func() int { return config.C.RateLimit.DailyProductPerIP })
dqShopList := middleware.DailyQuota("shoplist", func() int { return config.C.RateLimit.DailyShopListPerIP })
// 公开商品详情页(注入 OG 标签的 Flutter index.html,供社交分享爬虫读取)
r.GET("/product/:public_id", publicReadIP, publicH.ProductPage)
r.GET("/product/:public_id", publicReadIP, dqProduct, publicH.ProductPage)
v1 := r.Group("/api/v1")
@@ -77,8 +80,8 @@ func Setup(r *gin.Engine, db *gorm.DB) {
// 公开接口(无需登录):读接口防爬、写接口防刷
public := v1.Group("/public")
{
public.GET("/products/:public_id", publicReadIP, publicH.GetProduct)
public.GET("/shops/:shop_code/products", shopListIP, publicH.ListShopProducts)
public.GET("/products/:public_id", publicReadIP, dqProduct, publicH.GetProduct)
public.GET("/shops/:shop_code/products", shopListIP, dqShopList, publicH.ListShopProducts)
public.GET("/release", publicReadIP, publicH.GetRelease)
public.POST("/errors", errorsIP, errorReportH.Submit)
public.POST("/register", registerIP, authH.Register)