利用Github Action实现Hugo博客的IndexNow通知功能

我希望通过IndexNow来加速bing对我的Blog网站的收录,所以我设计了使用GitHub Actions,并利用Vercel官方原生的deployment_status(部署状态)事件来触发的IndexNow通知机制。

这样做有几个优势:

  1. 完全免费:GitHub Actions对私有仓库每月有2000分钟免费额度,完全够用。
  2. 精准触发:不需要在GitHub Action里“死等”Vercel部署完毕,而是Vercel部署成功后,主动通知 GitHub,GitHub再执行IndexNow推送。
  3. 避免无效推送:只有Vercel的 生产环境 (Production) 且部署 成功 (Success) 时才会触发,失败或预览环境(Preview)不会触发。

第一步:获取并配置IndexNow密钥到Hugo

IndexNow 要求你的网站根目录下必须有一个与密钥同名的 .txt 文件来验证所有权。

  1. 去Bing Webmaster Tools生成一个IndexNow API Key。
  2. 在Hugo 项目的根目录的static文件夹下,新建一个文本文件,文件名就是你的密钥,例如 1a2b3c4d5e6f7g8h9i0j.txt
  3. 文件里面的内容也只写这串密钥:1a2b3c4d5e6f7g8h9i0j
  4. 在本地运行hugo server,确保通过 https://localhost:1313/1a2b3c4d5e6f7g8h9i0j.txt可以访问到这个文件。

第二步:在GitHub仓库中配置Secret

为了安全,不要把密钥明文写在代码里。

  1. 去GitHub博客私有仓库。
  2. 点击 Settings -> Secrets and variables -> Actions。
  3. 点击 New repository secret。
  4. Name 填入:INDEXNOW_KEY
  5. Secret 填入密钥(例如 1a2b3c4d5e6f7g8h9i0j),点击Add secret保存。

第三步:编写 GitHub Actions 配置文件

在Hugo 项目根目录下,依次创建文件夹 .github/workflows/,并在里面新建一个文件,比如叫 indexnow.yml

将以下代码完整复制进去(注意修改里面标了“修改这里”的地方):

Copy

name: Submit to IndexNow on Vercel Success

# 监听部署状态事件
on:
  deployment_status:

jobs:
  indexnow:
    # 只有当部署成功,并且是生产环境(不是 Preview)时才执行
    if: github.event.deployment_status.state == 'success' && github.event.deployment_status.environment == 'Production'
    runs-on: ubuntu-latest

    steps:
      - name: Send Sitemap to IndexNow
        env:
          INDEXNOW_KEY: ${{ secrets.INDEXNOW_KEY }}
          # 【修改这里】换成你自己的真实域名,不要结尾的斜杠
          SITE_URL: "https://www.yourdomain.com"
        # 使用 Python 脚本自动抓取最新的 Sitemap 并提交给 IndexNow
        run: |
          python -c "
          import urllib.request, xml.etree.ElementTree as ET, json, os

          site_url = os.environ['SITE_URL']
          key = os.environ['INDEXNOW_KEY']
          host = site_url.replace('https://', '').replace('http://', '')

          print(f'Fetching sitemap from: {site_url}/sitemap.xml')
          try:
              # 1. 获取 Hugo 生成并由 Vercel 发布的 sitemap.xml
              req = urllib.request.Request(f'{site_url}/sitemap.xml', headers={'User-Agent': 'Mozilla/5.0'})
              xml_data = urllib.request.urlopen(req).read()

              # 2. 解析 XML,提取所有的 URL
              root = ET.fromstring(xml_data)
              ns = {'ns': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
              urls = [elem.text for elem in root.findall('ns:url/ns:loc', ns)]

              print(f'Found {len(urls)} URLs in sitemap.')

              # 3. 构造 IndexNow 需要的 JSON 数据
              data = {
                  'host': host,
                  'key': key,
                  'keyLocation': f'{site_url}/{key}.txt',
                  'urlList': urls
              }

              # 4. 发送 POST 请求到 IndexNow API
              req_post = urllib.request.Request(
                  'https://api.indexnow.org/indexnow', 
                  data=json.dumps(data).encode('utf-8'), 
                  headers={'Content-Type': 'application/json; charset=utf-8'}
              )
              response = urllib.request.urlopen(req_post)

              print(f'IndexNow Response Status: {response.status}')
              if response.status in [200, 202]:
                  print('✅ Successfully submitted to IndexNow!')
              else:
                  print('❌ Submission might have failed.')

          except Exception as e:
              print(f'❌ Error: {e}')
              exit(1)
          "          

第四步:提交代码并验证

  1. 将更改 git add . -> git commit -m "add indexnow action" -> git push 到你的 GitHub。
  2. 此时Vercel会开始构建你的博客。
  3. 重点:去GitHub仓库的 Actions 页面观察。
  4. 当Vercel部署完成后,Vercel会回传一个Success状态给GitHub。
  5. 这时你会看到名为 Submit to IndexNow on Vercel Success 的Action被自动触发。
  6. 点进去看日志,如果看到 Found XX URLs in sitemap. 和 ✅ Successfully submitted to IndexNow!,就说明大功告成了!

上面的方案不需要计算文件差异 (git diff)。博客文章多了以后,计算每次修改了哪个Markdown文件并转换为对应的URL非常复杂。这个脚本直接读取你刚部署上线的最新的 sitemap.xml,把所有URL打包发给IndexNow(IndexNow 允许每天提交 10,000 个 URL,对绝大多数博客绰绰有余)。

这个方案同时又容错率极高。如果你的Vercel构建失败(比如写错了Hugo短代码),Vercel传给GitHub的状态是 failure,Action根本不会运行,从而避免了向Bing提交错误的网站状态。

内容声明与版权协议

  • 版权协议:本文采用 CC BY-NC-SA 4.0(署名-非商业性使用-相同方式共享) 协议进行许可。转载、演绎请务必保留作者署名及原文链接,且不得用于商业目的。
  • AI 辅助说明:本博客部分内容(如排版设计、个别局部、特定对话片段等)可能由 AI(LLM大语言模型)辅助生成。作者在此明确声明:本人对文章的核心框架、思想立论与最终呈现拥有绝对主导权与最终解释权。
  • 观点免责:文中明示的由 AI 生成的特定文本、对话输出,仅作为理性探讨以及观点展示,不代表本人真实立场、价值观或事实背书。对于因 AI 幻觉造成的客观事实偏差,请读者审慎甄别。
  • 认知时效性:文章仅代表作者在撰写当下的认知状态与情绪切片。随着个人心智迭代与客观事物发展,作者观点可能发生演变。欢迎基于理性的交流与批评。