14 KiB
后端 Sitemap 生成对接规则
核对时间:2026-10-22 22:53(Asia/Shanghai)。
本文根据当前工作区的前端代码(包含尚未提交的修改)整理固定页面、URL、canonical 和 noindex 规则,供后端实现 sitemap 生成。它描述现有页面行为及生成约定,不表示 sitemap、存储或 Nginx 已完成接入。
当前内容主地址仅优先使用符合英文/拼音字符规则的 slug;中文、已编码中文或其他无效 slug 回退到 ID。搜索关键词仍支持中文和特殊字符,但所有搜索地址均排除在 sitemap 外。
1. 域名与通用约定
D表示正式站点的 origin,即协议、域名和可选端口,不带末尾/。- 域名优先取
config.config.foreverUrlAddr;无有效值时取config.newAddressInfo.foreverUrlAddr。移除配置中的路径、查询参数和锚点,与前端 canonical 保持一致。 - 不使用 API 域名、CDN 域名、请求 Host、临时访问域名或本地地址作为页面域名。
- 生成任务没有有效正式域名时,不猜测域名;暂停本次发布并保留上一份成功结果。
- 页面 URL 以
/结尾;sitemap 中使用绝对地址D + 规范路径。 - sitemap 只提交正常、允许索引的页面及其 canonical 地址;别名、参数变体和重复地址不单独提交。
- API、媒体源、静态资源和健康检查不属于本文的页面 sitemap 范围。
2. 固定页面清单
固定地址候选共 12 个。满足条件时,其 canonical 均为 D + URL。列表为空或页面异常时,按后续排除规则处理。
| 页面 | URL | 加入 sitemap 的条件 |
|---|---|---|
| 首页 | / |
页面正常 |
| 短剧列表 | /shorts/ |
页面正常且列表非空 |
| 专题列表 | /topics/ |
页面正常且列表非空 |
| 热播榜 | /rank/hot/ |
页面正常且列表非空 |
| 新剧榜 | /rank/new/ |
页面正常且列表非空 |
| 追剧榜 | /rank/follow/ |
页面正常且列表非空 |
| 关于我们 | /info/about-us/ |
页面正常 |
| 用户协议 | /info/user-agreement/ |
页面正常 |
| 隐私政策 | /info/privacy-policy/ |
页面正常 |
| 常见问题 | /info/help-center/ |
页面正常 |
| 2257 合规声明 | /info/2257/ |
页面正常 |
| DMCA 版权声明 | /info/dmca/ |
页面正常 |
这些是页面地址,不是需要前端预建的 sitemap XML 文件。
3. 动态页面 URL 规则
| 类型 | 规范 URL | 加入 sitemap 的条件 |
|---|---|---|
| 作品详情 | /detail/{key}/ |
作品存在,页面正常且未被标记为需登录或禁止索引 |
| 专题详情 | /topics/{key}/ |
专题存在,页面正常且列表非空 |
| 标签列表 | /tag/{key}/ |
标签存在,页面正常且列表非空 |
| 更多栏目 | /config/{key}/ |
首页栏目存在、已启用且类型为 1 或 3,并具有自己的标题、正文简介和有效内容卡片 |
| 单集播放 | /play/{作品key}/{chapterId}/ |
满足下述播放页条件 |
| 内容列表分页 | {列表基础路径}page/{n}/ |
n >= 2,分页真实存在且允许索引 |
3.1 内容标识
{key}优先使用内容接口返回的有效英文/拼音slug;无有效 slug 时使用正整数 ID。前端不会自动把中文转成拼音。- slug 去掉首尾空格后,必须满足
/^[a-z\d][a-z\d_-]*$/i:以 ASCII 字母或数字开头,其余只能包含 ASCII 字母、数字、连字符-、下划线_。 - 使用接口返回的规范大小写,作为一个路径段按
encodeURIComponent的语义编码一次,避免重复编码;不得把编码后的中文当作英文 slug。 - 中文、中文英文混合、内含空格、斜杠、点号、百分号、问号等不符合正则的 slug 均回退到 ID。
-city和_city也不符合开头规则。 - 历史中文 slug 地址在能够匹配到真实内容时仍可读取,但 canonical 和新生成链接使用 ID;后端不应继续向 sitemap 写入这些兼容地址。
- 纯数字路径按 ID 查询,不按 slug 查询。当前生成正则本身未单独排除纯数字 slug,因此后端应避免分配此类 slug;存量数据须核对身份,不能直接当作 slug 发布。
- 使用数字 ID 时去除前导零;ID 必须是正整数,且处于 JavaScript 安全整数范围内。
{chapterId}是真实章节 ID,不是集数,也不支持章节 slug。章节必须属于 URL 中的作品。
以作品 id=9 为例:
| 接口返回的 slug | 生成的详情路径 |
|---|---|
city-story |
/detail/city-story/ |
city_story-2026 |
/detail/city_story-2026/ |
dushiaiqing |
/detail/dushiaiqing/ |
City-Story |
/detail/City-Story/ |
都市爱情 |
/detail/9/ |
city-爱情 |
/detail/9/ |
%E9%83%BD%E5%B8%82 |
/detail/9/ |
city story、city/story、city.story、空值 |
/detail/9/ |
以上规则同时用于作品、专题、标签和更多栏目;播放页的作品段使用同一规则,章节段仍使用章节 ID。
3.2 播放页条件
播放页同时满足以下条件时才可进入公共 sitemap:
- 作品及章节真实存在,且两者对应。
- 有作品名和真实的正整数集数。
- 公开抓取身份有权观看当前章节。
- 存在有效的当前章节正片地址。
共享预告、继承的作品简介、章节 SEO 标题或纯解锁提示不能单独满足条件。收费类型本身不是排除依据,但不能使用管理员、VIP 或已购用户的个人权限生成公共 sitemap。
sitemap 提交页面 URL,不写入用户凭证或受限媒体源。
3.3 列表分页
- 普通内容目录当前每页 24 条,后端根据有效总数计算真实页数。
- 更多栏目当前使用有限首页栏目快照:类型
1取实际作品列表,类型3取实际专题列表,以实际条目数为totalCount。SEO 层取pageSize = max(24, totalCount),因此当前只发布栏目基础地址,不生成/config/{key}/page/2/等额外分页。 - 第一页只提交基础地址,不额外提交
/page/1/。 - 第 2 页及以后保留自己的 canonical,例如
/shorts/page/2/,不统一归并到第一页。 - 作品详情和播放页的
/page/{n}/是评论分页;n > 1时不进入 sitemap。 - 搜索、收藏、历史、已购和充值即使有分页,也不进入 sitemap。
4. Canonical 规则
| 场景 | 规范化规则 |
|---|---|
| 正式域名 | 统一使用 D,与前端页面 canonical 的域名一致 |
| 尾斜杠 | 页面路径以 / 结尾 |
| 查询参数和锚点 | canonical 不含查询参数和锚点;sitemap 同样不提交这些变体 |
| 第一页 | /shorts/page/1/ 规范化为 /shorts/;其他支持分页的页面同理 |
| 有效列表分页 | 第 2 页及以后自引用,保留 /page/{n}/ |
| 默认榜单 | /rank/ 规范化为 /rank/hot/;/rank/page/2/ 规范化为 /rank/hot/page/2/ |
| 专题别名 | /theme/{key}/ 规范化为 /topics/{规范key}/,保留有效分页 |
| ID 与 slug | 有符合英文/拼音字符正则的 slug 时,ID 地址指向 slug 主地址;中文或其他无效 slug 回退到规范 ID |
| 历史中文 slug 地址 | 能匹配到资源时保留兼容读取,canonical 使用该资源的规范 ID 地址 |
| 数字 ID 前导零 | 无 slug 时,/detail/009/ 规范化为 /detail/9/;其他数字内容 ID 同理 |
| noindex 页面 | 当前前端不输出 canonical,不进入 sitemap |
例如作品 id=9、slug=city-story,章节 ID 为 90:
/detail/9/ -> D/detail/city-story/
/detail/city-story/ -> D/detail/city-story/
/play/9/90/ -> D/play/city-story/90/
/play/city-story/90/ -> D/play/city-story/90/
例如专题 id=7、slug=city-collection:
/theme/7/ -> D/topics/city-collection/
/topics/7/ -> D/topics/city-collection/
/theme/7/page/2/ -> D/topics/city-collection/page/2/
例如作品 id=9、slug=都市爱情,章节 ID 为 90,中文仅用于展示或兼容读取:
/detail/9/ -> D/detail/9/
/detail/都市爱情/ -> D/detail/9/
/play/9/90/ -> D/play/9/90/
/play/都市爱情/90/ -> D/play/9/90/
上述中文路径按可读形式展示,实际请求可使用百分号编码;sitemap 只写入右侧 ID 主地址。
别名页面仍可允许索引,canonical 归并不等于 noindex,也不表示已有重定向。sitemap 只提交最终 canonical 地址,并按完整地址去重。
/home、/playlet、/list、/topic、/application 等值只用于后台导航值转换,不是额外公开页面,不应据此生成 sitemap 地址。
5. 固定 Noindex 页面
| 页面范围 | URL | 当前 robots |
|---|---|---|
| 搜索和搜索分页 | /search/、/search/{关键词}/、/search/{关键词}/page/{n}/、/search/?q={关键词}、/search/page/{n}/?q={关键词} |
noindex,follow |
| 独立入口 | /navigation/ |
noindex,follow |
| 回家的路 | /home-road/ |
noindex,follow |
| 福利应用 | /apps/ |
noindex,follow |
| 个人中心 | /member/center/、/info/user-center/ |
noindex,nofollow |
| 收藏 | /member/favorites/,包括分页 |
noindex,nofollow |
| 历史 | /member/history/,包括分页 |
noindex,nofollow |
| 已购 | /member/purchased/,包括分页 |
noindex,nofollow |
| 账号设置 | /member/settings/、/info/settings/ |
noindex,nofollow |
| 充值及 VIP | /info/deposit/、/info/deposit/vip/,包括支持的分页 |
noindex,nofollow |
| 意见反馈 | /info/feedback/ |
noindex,nofollow |
以上页面及其参数变体均不进入 sitemap。
5.1 当前搜索地址的排除规则
- 新生成的搜索入口统一使用
/search/{关键词}/;关键词先去掉首尾空格,再通过encodeURIComponent整体编码为一个路径段。 - 关键词可以包含中文、空格、斜杠、问号、百分号等字符。搜索关键词不受内容 slug 的 ASCII 正则限制,也不进行数字 ID 归一。
/search/?q={关键词}和/search/page/{n}/?q={关键词}仍可解析;后续分页链接生成路径形式并移除q参数,不依赖重定向完成转换。- 路径本身已有关键词时优先使用路径关键词;只有路径没有关键词时才从
q读取。 - 不论入口形式、搜索结果数量或关键词字符,搜索页始终
noindex,follow,不输出 canonical,也不进入 sitemap。 - 无关键词的
/search/可以访问;无关键词且页码大于 1 时返回 404。
6. 条件性 Noindex 与异常处理
| 情况 | 当前前端行为 | 后端生成处理 |
|---|---|---|
| 空公开列表 | 接口成功确认 totalCount=0 时,第一页 noindex,follow,仍返回 200 |
不提交 |
| 详情或播放页评论分页 | /detail/{key}/page/{n}/、/play/{key}/{chapterId}/page/{n}/,n>1 时 noindex,follow |
不提交 |
| 非默认列表排序 | 除榜单和更多栏目外,公开列表 sort != 1 时 noindex |
只生成无参数的默认地址 |
| 非法列表排序 | 公开列表的 sort 不属于 1、2、3 时 noindex;未传时默认 1 |
不生成非法变体 |
| 非默认评论排序 | 存在 commentSort 且值不等于字符串 2 时 noindex |
不生成参数变体 |
| 更多栏目内容不足或无效 | 已存在栏目缺少自己的标题、正文简介或有效卡片时 noindex,follow;找不到启用的类型 1/3 栏目时按资源缺失处理 |
不提交 |
| 播放页条件不足 | 预告、纯解锁提示、无有效正片或无观看权限时 noindex,follow |
不提交 |
| 明确禁止索引或需要登录 | indexable=false 或 loginRequired=true 时 noindex |
不提交 |
| 无效路由或不存在的资源 | 返回 404,且无 canonical | 不提交 |
| 已确认越界的分页 | 返回 404,且无 canonical | 不提交 |
| 临时取数故障 | failed 或 unavailable 时返回 500,且无 canonical |
不将故障误判为删除;保留上次成功结果,稍后重试 |
补充约定:
- 榜单和更多栏目可以接受
sort=2/3,但 canonical 仍不含参数;sitemap 不重复提交这些参数地址。 - 作品详情的评论数为 0,不等于作品内容为空,不能按空列表规则排除作品详情。
- 不存在的内容与临时故障必须区分;无法可靠判断一批内容时,不发布因取数失败而缺项的新结果。
7. 建议的生成与发布约定
- 合并本文的固定地址与后端数据库枚举的动态内容。
- 按公开访问时的页面状态判断是否允许索引。
- 按英文/拼音 slug 白名单和 ID 回退规则生成最终 canonical URL,不输出参数、锚点、别名、中文内容 slug 或非页面资源。
- 按完整 canonical URL 去重,只发布正常、有效的页面地址。
lastmod有可靠数据时使用页面内容实际更新时间;没有时省略,不统一伪造为生成时间。- 生成文件保存到前端发布目录之外的持久化存储,不写入前端
public或.next。 - 完成分片生成和可访问性校验后,再切换 sitemap 索引;失败时保留上一份成功版本。
- 建议固定入口为
/sitemap.xml,分片通过/sitemaps/下的通用路径提供访问。现有入口不同时,优先保留已提交的地址。 robots.txt中声明正式站点的 sitemap 索引地址;前后端 URL 或索引规则变更时同步更新生成逻辑。
首次接入需要部署访问配置;后续内容和分片变化不应要求前端预留文件、重新构建或重启 H5。
8. 代码依据
- 路由解析、内容路径和分页支持
- 域名、canonical、noindex 和页面状态判断
- 服务端资源核对与 SEO 元数据输出
- 专题解析、首页栏目快照和列表分页
- 章节权限与正片地址判断
- 固定信息页
- 现有页面索引策略(其“非空 slug 优先”描述需结合当前代码的英文/拼音字符白名单理解)
- SEO 规则回归用例
- Slug 路由与 canonical 回归用例
- 路由与搜索参数兼容回归用例
- 分页与搜索路径回归用例