Appearance
VitePress 博客秒收录:Bing IndexNow + GitHub Actions 自动化实战

最近在查阅 Bing Webmaster Tools 后台时,系统给我推送了一条重要的优化建议:
"了解 IndexNow 如何通过简单的 5 分钟设置提高网站在搜索引擎中的可见性"
查看后台数据,虽然总曝光有 5.6K,但点击量仅有 202 次,且数据曲线波动极大。这说明网站的新内容并未得到搜索引擎的及时抓取。由于我的博客是基于 VitePress 构建的纯静态站点,没有 WordPress 那样现成的插件生态,于是我决定自己动手,通过 API 推送和 CI 流程来实现自动收录。
今天,我们就来实操一下,如何为你的 VitePress 博客接入 IndexNow,实现“发文即收录”的丝滑体验。
什么是 IndexNow?
传统 SEO 流程中,我们发布文章后只能被动等待搜索引擎的“蜘蛛”爬虫定期来抓取(可能耗时几天到几周)。
IndexNow 是由 Microsoft Bing 和 Yandex 联合推出的一项开源协议。它的核心理念是:主动推送。当你的网站内容发生更新时,你通过 API 立即通知搜索引擎,搜索引擎收到通知后会第一时间来处理。
简单来说:把“等快递”变成了“发顺丰特快”。
第一步:生成并部署 API Key(VitePress 专属配置)
第一步永远是在 Bing Webmaster Tools 中获取一个专属的 Key,并验证网站所有权。
- 登录 Bing Webmaster Tools。
- 在左侧菜单找到并点击 IndexNow。
- 系统会为你生成一串 API Key(例如:
74c02e84c5fe401bb1768e0eae41deb6)。 - 核心验证步骤(VitePress 实操):
- 你的 Key 需要能被公网直接访问到:
https://fishfinal.com/74c02e84c5fe401bb1768e0eae41deb6.txt。 - 由于 VitePress 构建后的产物在
.vitepress/dist,你只需要将74c02e84c5fe401bb1768e0eae41deb6.txt文件放入你的docs/public/目录中。 - 文件内容仅需填写这串 Key 本身。
- 重新
build并发布你的 VitePress 站点,在浏览器中确认该链接可访问,即代表验证通过。
- 你的 Key 需要能被公网直接访问到:
第二步:VitePress 开发者方案(GitHub Actions 自动化推送)
作为 VitePress 博主,我们追求的是自动化。每次发布新文章,还要手动跑一遍脚本太麻烦了。我们可以利用 GitHub Actions,在每次 push 到 main 分支时,自动提取本次提交中新增或修改的 .md 文件路径,将其转换为 URL 并推送给 IndexNow。
1. 编写推送脚本
在你的项目根目录创建一个脚本文件 scripts/indexnow.mjs(这里使用 Node.js 原生 fetch,无需额外依赖):
javascript
// ====== 配置区 ======
const HOST = 'fishfinal.com'
const KEY = '74c02e84c5fe401bb1768e0eae41deb6'
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`
const ENDPOINT = 'https://api.indexnow.org/indexnow'
// 严格限制只推送 posts 目录下的文章
const POSTS_PREFIX = 'docs/posts/'
// ====================
import fs from 'node:fs'
function writeOutput(key, value) {
if (!process.env.GITHUB_OUTPUT) return
fs.appendFileSync(process.env.GITHUB_OUTPUT, `${key}=${value}\n`)
}
function writeUrlsToOutput(urls) {
const html = urls.map(u => `<li><a href="${u}">${u}</a></li>`).join('')
writeOutput('pushed_urls_html', html)
writeOutput('pushed_count', String(urls.length))
}
function writeErrorToOutput(msg) {
writeOutput('error_msg', msg.replace(/\n/g, '<br>'))
}
// ====== 1. 解析过滤文件 ======
const changedFiles = process.env.CHANGED_FILES
? process.env.CHANGED_FILES.split(' ').filter(Boolean)
: []
// 只保留 docs/posts/ 下的 .md 文件,过滤掉配置文件、脚本等
const mdFiles = changedFiles.filter(
file => file.startsWith(POSTS_PREFIX) && file.endsWith('.md')
)
if (mdFiles.length === 0) {
console.log('ℹ️ docs/posts/ 下没有新增或修改的 Markdown 文章,跳过 IndexNow 推送。')
writeOutput('pushed_count', '0')
process.exit(0)
}
// ====== 2. 转换为完整 URL ======
let urlList = mdFiles.map(file => {
// docs/posts/seo/xxx.md -> /posts/seo/xxx
let urlPath = file.replace(/^docs/, '').replace(/\.md$/, '.html')
urlPath = urlPath.replace(/\/index$/, '/')
if (urlPath === '') urlPath = '/'
return `https://${HOST}${urlPath}`
})
// 过滤 404 并去重
urlList = [...new Set(urlList.filter(url => !url.includes('/404')))]
// ====== 3. 真实可用性校验 (防止给 Bing 推送 404) ======
async function verifyUrls(urls) {
const valid = []
console.log('\n🔍 开始校验 URL 是否真正可访问 (HEAD 请求):')
for (const url of urls) {
try {
const res = await fetch(url, { method: 'HEAD' })
if (res.ok) {
console.log(` ✅ [${res.status}] ${url}`)
valid.push(url)
} else {
console.warn(` ❌ [${res.status}] ${url} (跳过推送)`)
}
} catch (e) {
console.warn(` ❌ 请求失败 ${url} (跳过推送)`)
}
}
return valid
}
// ====== 4. 发送请求 ======
async function main() {
const verifiedUrls = await verifyUrls(urlList)
if (verifiedUrls.length === 0) {
console.log('\n⚠️ 所有 URL 校验均未通过(可能网站还未部署完成或存在 CDN 缓存),终止推送。')
writeErrorToOutput('URL 校验失败,无法访问实际页面')
process.exit(1)
}
const payload = {
host: HOST,
key: KEY,
keyLocation: KEY_LOCATION,
urlList: verifiedUrls,
}
// 打印你要求的完整 Request Body
console.log('\n📤 即将推送到 IndexNow 的完整请求体:')
console.log('─────────────────────────────────────────')
console.log(JSON.stringify(payload, null, 2))
console.log('─────────────────────────────────────────')
try {
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json; charset=utf-8' },
body: JSON.stringify(payload),
})
const responseText = await response.text()
console.log(`\n📨 响应状态码: ${response.status}`)
if (responseText) console.log(`📨 响应内容: ${responseText}`)
// 严格按照官方文档:只有 200 是成功
if (response.status === 200) {
console.log('\n✅ [200 OK] URL 提交成功!')
writeUrlsToOutput(verifiedUrls)
process.exit(0)
} else if (response.status === 202) {
// 针对 202 的特殊说明
console.log('\n⚠️ [202 Accepted] 请求已被接收,正在排队处理(Bing 通常会在稍后异步完成抓取)。')
writeUrlsToOutput(verifiedUrls)
process.exit(0) // 依然视为流程成功
}
// 失败分支
let errMsg = ''
switch (response.status) {
case 400: errMsg = '[400 Bad Request] 请求格式无效'; break;
case 403: errMsg = `[403 Forbidden] Key 无效。请检查:\n 1. 文件是否可通过 ${KEY_LOCATION} 访问?\n 2. 文件内容是否与 KEY 完全一致?`; break;
case 422: errMsg = '[422 Unprocessable Entity] URL 不属于该 host,或 Key 与协议 schema 不匹配'; break;
case 429: errMsg = '[429 Too Many Requests] 推送过于频繁'; break;
default: errMsg = `[${response.status}] 未知状态码,响应: ${responseText}`;
}
console.error(`\n❌ ${errMsg}`)
writeErrorToOutput(errMsg)
process.exit(1)
} catch (error) {
const errMsg = `网络请求异常: ${error.message}`
console.error(`\n❌ ${errMsg}`)
writeErrorToOutput(errMsg)
process.exit(1)
}
}
main()2. 配置 GitHub Actions
在你的项目根目录创建 .github/workflows/indexnow.yml 文件:
yaml
name: Push to Bing IndexNow
on:
push:
branches:
- master # 你的主分支名称,按需修改
jobs:
indexnow:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2 # 拉取最近两次提交,用于对比 diff
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Get changed files
id: changed-files
run: |
# 获取本次 push 中新增(A)或修改(M)的文件列表,并输出到环境变量
FILES=$(git diff --name-only HEAD^ HEAD --diff-filter=AM | tr '\n' ' ')
echo "CHANGED_FILES=$FILES" >> $GITHUB_ENV
- name: Run IndexNow Push Script
run: node scripts/indexnow.mjs
env:
CHANGED_FILES: ${{ env.CHANGED_FILES }}3. 提交并触发
将这两个文件提交到你的 GitHub 仓库,并随便修改一篇你的 Markdown 文章然后 push。去 GitHub Actions 面板查看,你就会看到脚本自动提取了那篇文章的 URL,并成功推送给了 Bing。
为什么 Bing 会疯狂提示我用 IndexNow?
回到文章开头的数据:
- 点击次数:202
- 总印象数:5.6K
Bing 的逻辑很清晰:我的站内有很多新页面没有被及时索引,无法参与排名竞争。通过上面的 GitHub Actions 自动化,我将彻底解决“收录慢”的问题。
⚠️ 重要提醒: 收录快 ≠ 排名好。IndexNow 只能帮我解决“被看到”的问题(加速收录),而“排在前面”(提升排名)依然需要依靠高质量的内容和优质的外链建设。
最终效果
配置完成后,你可以在 Bing 后台的 IndexNow 菜单中查看推送历史。现在,你的 VitePress 博客每一次发布,都能在几分钟内被 Bing 知晓。赶紧动手试试吧!
