跳转到正文
Monster Cone
返回

IndexNow 是什么?Next.js 博客接入搜索引擎主动推送

编辑页面

做个人博客时,文章发布后最常见的等待就是:搜索引擎什么时候来抓取?传统方式主要依赖站点地图、内链和爬虫定期访问。它稳定,但不够主动,尤其是博客更新频率不高时,新文章被发现可能会有明显延迟。

IndexNow 解决的就是这个问题:当页面新增、更新或删除时,网站可以主动把 URL 通知给支持该协议的搜索引擎。搜索引擎收到通知后,再决定是否抓取和更新索引。它不是“提交后立刻排名”的魔法按钮,但对内容发现速度和爬虫效率很有帮助。

这篇文章记录一下 IndexNow 的基本原理,以及如何在 Next.js + Vercel 的博客项目里,把 URL 提交流程自动挂到构建之后。

IndexNow 是什么

IndexNow 是一个开放协议,用来通知搜索引擎某些 URL 发生了变化。它的核心流程很简单:

  1. 生成一个站点专属 key。
  2. 在站点根路径放置 {key}.txt 文件,文件内容就是这个 key。
  3. 当页面发生变化时,通过 HTTP 请求把 URL 和 key 提交给 IndexNow API。

官方文档提供了两种提交方式:

批量提交的 JSON 结构大致是这样:

{
  "host": "www.example.com",
  "key": "your-indexnow-key",
  "urlList": [
    "https://www.example.com/post-1",
    "https://www.example.com/post-2"
  ]
}

如果请求返回 200,表示 URL 已成功提交;如果返回 202,表示 URL 已收到,但 key 校验还在等待中。常见错误包括 key 文件不可访问、URL 不属于当前 host、格式错误或提交过于频繁。

官方文档可以看这里:IndexNow Documentation。

它适合解决什么问题

对个人博客、文档站、产品内容页来说,IndexNow 很适合下面几类场景:

不过它也有边界:

简单说,IndexNow 是 SEO 基础设施里的一个“主动通知”能力,而不是 SEO 本身。

生成并放置 key 文件

IndexNow 需要通过 key 文件验证站点所有权。key 可以自己生成,只要满足长度和字符要求即可。比如使用 UUID:

node -e "console.log(crypto.randomUUID())"

假设生成的 key 是:

73f35cf4-6bf6-4a92-a86e-3de50a80bc76

那么需要在 public 目录下创建一个同名文本文件:

public/73f35cf4-6bf6-4a92-a86e-3de50a80bc76.txt

文件内容也写这个 key:

73f35cf4-6bf6-4a92-a86e-3de50a80bc76

部署后,搜索引擎应该能访问到:

https://www.example.com/73f35cf4-6bf6-4a92-a86e-3de50a80bc76.txt

这个 key 文件不是传统意义上的后端密钥,因为它本来就需要被搜索引擎访问。真正要注意的是:不要频繁变更它,否则搜索引擎需要重新校验。

在站点配置里保存 key

我的博客本身有一个 siteMetadata 配置文件,所以直接把 IndexNow key 放进去:

const siteMetadata = {
  siteUrl: "https://www.example.com",
  indexNowKey: "73f35cf4-6bf6-4a92-a86e-3de50a80bc76",
};

module.exports = siteMetadata;

如果你更希望通过环境变量管理,也可以只在 Vercel 中配置 INDEXNOW_KEY,脚本里优先读取环境变量,再回退到站点配置。

编写提交脚本

接下来写一个 scripts/indexnow.mjs。核心思路是:

下面是一个简化版脚本:

import siteMetadata from "../data/siteMetadata.js";

const ENDPOINT = "https://api.indexnow.org/indexnow";

async function submitIndexNow(urlList) {
  const siteUrl = siteMetadata.siteUrl.replace(/\/$/, "");
  const host = new URL(siteUrl).host;
  const key = process.env.INDEXNOW_KEY || siteMetadata.indexNowKey;

  if (!key || !urlList.length) return;

  const response = await fetch(ENDPOINT, {
    method: "POST",
    headers: {
      "Content-Type": "application/json; charset=utf-8",
    },
    body: JSON.stringify({
      host,
      key,
      urlList,
    }),
  });

  if (response.status === 200 || response.status === 202) {
    console.log(`IndexNow submitted ${urlList.length} URLs.`);
    return;
  }

  console.warn(`IndexNow submission returned ${response.status}.`);
}

实际项目里,URL 可以来自 sitemap、CMS、Contentlayer 生成的数据,或者你自己的路由配置。对于静态博客来说,最方便的是在构建后直接把文章页、列表页、分类页都收集出来。

例如:

const staticRoutes = ["", "about", "blog", "categories"];
const staticUrls = staticRoutes.map(route =>
  `${siteUrl}/${route}`.replace(/\/$/, "")
);

const blogUrls = allBlogs
  .filter(post => !post.draft)
  .map(post => `${siteUrl}/${post.path.replace(/^\//, "")}`);

const urlList = [...new Set([...staticUrls, ...blogUrls])];

new Set() 用来去重,避免同一个 URL 被重复提交。

接入 Next.js 的 postbuild

我更推荐把 IndexNow 放在构建后执行,而不是在页面请求时执行。原因有三个:

如果项目已经有 scripts/postbuild.mjs,直接引入即可:

import rss from "./rss.mjs";
import indexNow from "./indexnow.mjs";

async function postbuild() {
  await rss();
  await indexNow();
}

postbuild();

然后在 package.json 的 build 命令里接上 postbuild:

{
  "scripts": {
    "build": "next build && node ./scripts/postbuild.mjs"
  }
}

这样每次 Vercel 构建完成后,就会自动提交最新 URL。

给本地和预览环境加开关

本地调试时通常不希望真的提交给搜索引擎,所以可以加一个环境变量:

INDEXNOW_SUBMIT=dry-run npm run build

脚本里判断一下:

if (process.env.INDEXNOW_SUBMIT === "dry-run") {
  console.log(`IndexNow dry run: ${urls.length} URLs ready.`);
  return;
}

if (process.env.INDEXNOW_SUBMIT === "false") {
  console.log("IndexNow skipped.");
  return;
}

如果你在 Vercel 上有 Preview Deployment,也建议在预览环境里设置:

INDEXNOW_SUBMIT=false

正式生产环境不要设置这个变量,或者保持为空,这样部署后才会真实提交。

部署后怎么验证

部署完成后,可以先检查 key 文件是否能访问:

https://www.example.com/your-indexnow-key.txt

然后看 Vercel 的构建日志,正常情况下会看到类似输出:

IndexNow submitted 56 URLs (200).

如果返回 202 也不用慌,它表示搜索引擎已经收到 URL,但 key 校验还在处理中。第一次接入时比较常见。

如果返回 403,优先检查:

如果返回 422,通常是 URL 和 host 不匹配,比如提交了 example.com,但 host 写的是 www.example.com。

和 sitemap 的关系

IndexNow 不应该替代 sitemap。更合理的搭配是:

也就是说,sitemap 是长期地图,IndexNow 是变更通知。两者一起用,才是比较稳的方案。

小结

IndexNow 的接入成本很低:一个 key 文件,一个提交脚本,再把它挂到构建流程里就可以了。对个人博客来说,它最实用的价值不是“提升排名”,而是让搜索引擎更快知道站点发生了变化。

如果你已经有自动部署流程,建议把 IndexNow 放到 postbuild 阶段;如果你使用 CMS,也可以在文章发布、更新、删除时触发提交。无论哪种方式,记住一点就够了:只在内容真的发生变化时提交,别把它当成定时刷接口。


编辑页面
分享这篇文章:

上一篇
使用 QStash 实现 FCM 定时推送通知
下一篇
Nginx Proxy Manager 可视化配置 Nginx:搭配 Dozzle 和 NginxPulse 查看日志