feat: 新增 IndexNow 批量提交接口(主页 + 专题)
POST /api/web/seopush/indexnow/bulk?limit=10
- 组装主页 "/" 和前 N-1 个专题(playlet_theme 按 Rank 降序)URL
- 调用 pub/seo/indexnow.BatchIndexNowSubmitter 提交到 api.indexnow.org
- 返回提交的 URL 列表 + IndexNow 回执(含各引擎 HTTP 状态码)
- Admin 鉴权(走 /api/web/* 的 auth 中间件)
部署前提:
- web.yaml 配置 indexNow.key
- Web 根目录可访问 /{key}.txt(内容为 key 本身)作为 IndexNow 域名验证
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
package web_seopush
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"hkdj-web-server/pub/common"
|
||||||
|
"hkdj-web-server/pub/common/srvdef"
|
||||||
|
"hkdj-web-server/web/service/srv_seopush"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags SEO推送
|
||||||
|
// @Summary IndexNow 批量提交(主页 + 专题)
|
||||||
|
// @Description 组装主页和前 N 个专题(按 Rank 降序)地址,提交到 IndexNow(Bing / Yandex 等)。
|
||||||
|
// @Produce json
|
||||||
|
// @Param limit query int false "URL 总数,含主页,默认 10"
|
||||||
|
// @Success 200 {object} srv_seopush.BulkIndexNowResult
|
||||||
|
// @Router /api/web/seopush/indexnow/bulk [POST]
|
||||||
|
func SubmitHomeAndThemes(ctx *gin.Context) {
|
||||||
|
limit, _ := strconv.Atoi(ctx.Query("limit"))
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 10
|
||||||
|
}
|
||||||
|
resp, serr := srv_seopush.SubmitHomeAndThemes(ctx, limit)
|
||||||
|
if serr != nil {
|
||||||
|
common.ServerJSON(ctx, serr.Code, serr.Msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||||
|
}
|
||||||
@@ -95,6 +95,7 @@ func registerRouter(router *gin.Engine) {
|
|||||||
homeConfigRouter(rootRouter)
|
homeConfigRouter(rootRouter)
|
||||||
feedbackRouter(rootRouter)
|
feedbackRouter(rootRouter)
|
||||||
contactUsRouter(rootRouter)
|
contactUsRouter(rootRouter)
|
||||||
|
seopushRouter(rootRouter)
|
||||||
}
|
}
|
||||||
// 第三方回调路由(免鉴权,挂在 engine 上而非 /api/web 分组)
|
// 第三方回调路由(免鉴权,挂在 engine 上而非 /api/web 分组)
|
||||||
thirdRouter(router)
|
thirdRouter(router)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hkdj-web-server/web/api/web_seopush"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func seopushRouter(root *gin.RouterGroup) {
|
||||||
|
group := root.Group("/seopush")
|
||||||
|
{
|
||||||
|
group.POST("/indexnow/bulk", web_seopush.SubmitHomeAndThemes)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package srv_seopush
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"hkdj-web-server/pub/common/log"
|
||||||
|
"hkdj-web-server/pub/common/srvdef"
|
||||||
|
"hkdj-web-server/pub/models/playletthememod"
|
||||||
|
"hkdj-web-server/pub/seo/h5path"
|
||||||
|
seoindexnow "hkdj-web-server/pub/seo/indexnow"
|
||||||
|
"hkdj-web-server/web/webg"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BulkIndexNowResult 批量提交结果,包含提交的 URL 列表和 IndexNow 原始回执。
|
||||||
|
type BulkIndexNowResult struct {
|
||||||
|
URLs []string `json:"urls"`
|
||||||
|
SubmitInfo *seoindexnow.BatchResult `json:"submitInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubmitHomeAndThemes 组装主页 + 前 N 个专题(按 Rank 降序)URL,批量提交 IndexNow。
|
||||||
|
// limit 为 URL 总数(包含主页),默认 10;小于等于 1 时视为仅主页。
|
||||||
|
func SubmitHomeAndThemes(ctx context.Context, limit int) (*BulkIndexNowResult, *srvdef.SrvErr) {
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 10
|
||||||
|
}
|
||||||
|
webAddr := SEOBaseURL(ctx)
|
||||||
|
if webAddr == "" {
|
||||||
|
return nil, srvdef.New(srvdef.ErrNoData, "WebAddr 未配置", "")
|
||||||
|
}
|
||||||
|
key := strings.TrimSpace(webg.Conf.IndexNow.Key)
|
||||||
|
if key == "" {
|
||||||
|
return nil, srvdef.New(srvdef.ErrNoData, "indexNow.key 未配置", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
urls := make([]string, 0, limit)
|
||||||
|
urls = append(urls, h5path.Abs(webAddr, "/"))
|
||||||
|
if remain := limit - 1; remain > 0 {
|
||||||
|
themes, err := playletthememod.FindManyPlayletTheme(ctx,
|
||||||
|
bson.M{playletthememod.FN.PlayletTheme.Status: true},
|
||||||
|
options.Find().
|
||||||
|
SetSort(bson.M{playletthememod.FN.PlayletTheme.Rank: -1}).
|
||||||
|
SetLimit(int64(remain)))
|
||||||
|
if err == nil {
|
||||||
|
for _, t := range themes {
|
||||||
|
if t == nil || t.Id <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path := h5path.TopicDetail(t.Slug, t.Id)
|
||||||
|
if path == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
urls = append(urls, h5path.Abs(webAddr, path))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warn("seopush bulk: list themes failed", log.E(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config, cerr := seoindexnow.BuildConfig(webAddr, key)
|
||||||
|
if cerr != nil {
|
||||||
|
return nil, srvdef.New(srvdef.Failure, fmt.Sprintf("构造 IndexNow 配置失败: %v", cerr), "")
|
||||||
|
}
|
||||||
|
result := seoindexnow.NewBatchIndexNowSubmitter(config).SubmitBatch(urls)
|
||||||
|
log.Info("seopush bulk: indexnow submitted",
|
||||||
|
log.Any("urls", urls),
|
||||||
|
log.Any("statusCodes", result.StatusCodes),
|
||||||
|
log.Any("success", result.SuccessCount),
|
||||||
|
log.Any("fail", result.FailCount))
|
||||||
|
return &BulkIndexNowResult{URLs: urls, SubmitInfo: result}, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user