解放生产力:通过 GitHub Action 与 Cloudflare Worker 实现博客文章自动提交至必应
- 前言 📝
- 对于我们这些博主来说,写完一篇文章后,最重要的事情之一就是让搜索引擎尽快收录它。
- 每次都手动去必应站长平台提交新文章的 URL,不仅繁琐,而且容易忘记,久而久之就成了个麻烦事 😩。
- 本教程将带你设置一个“无服务器”的全自动化流程:当你用
git push
推送新文章到 GitHub 仓库时,它会自动将文章链接提交给必应。一次配置,永久省心 ✅。 - 本教程需要你有一个域名托管在 Cloudflare,并且对 GitHub Actions 有最基本的了解。
- 方案概述 🗺️ 整个自动化流程分为两个核心部分:
- Cloudflare Worker ☁️:一个轻量级的无服务器脚本,它接收一个文件名列表,然后负责调用必应的 API 来提交最终的 URL。
- GitHub Action 🚀:一个在你的仓库中运行的工作流,它会在你每次推送代码时被触发,找出新添加的文章,然后通知上面的 Cloudflare Worker 来干活。
听起来很简单,对吧我们这就开始。
- 第一部分:配置 Cloudflare Worker ⚙️
我们的 Worker 是一个独立的 TypeScript 项目,专门用来处理来自 GitHub 的请求。
-
创建 Worker 目录 首先,在你的项目根目录创建一个新文件夹,比如
bing-submit-worker
。 -
编写 Worker 代码 (
index.ts
) 这是 Worker 的核心逻辑。它会监听 POST 请求,解析请求中包含的文件名,拼接成完整的 URL,然后发送给必应。 -
配置 Worker (
wrangler.toml
) 这个文件告诉 Cloudflare 如何部署你的 Worker。我们在这里明确了它的名称、入口文件以及最重要的——构建方式和模块格式,以避免一些常见的部署错误。 -
项目依赖 (
package.json
和tsconfig.json
) 这两个文件用于管理项目依赖和 TypeScript 编译选项,确保我们的代码能在本地被正确识别,并且能成功构建。
- 第二部分:配置 GitHub Action 🔗
这是连接代码仓库和 Cloudflare Worker 的桥梁。
-
创建工作流文件 在你的仓库中,创建
.github/workflows/bing-submit.yml
文件。 -
编写工作流脚本 这个脚本会在每次向
src/content/posts/
目录推送新.md
文件时触发。它使用git diff --name-only --diff-filter=A
命令来精确地找出那些新添加的文件,忽略对旧文件的修改。然后,它通过curl
命令,将这些新文件名发送给我们刚刚部署的 Cloudflare Worker。
- 环境变量配置 🔑 为了让整个流程正常工作,我们需要配置两个关键的“秘密”变量。这可以确保我们的 API 密钥等敏感信息不会被硬编码在代码里。
-
BING_API_KEY
(用于 Cloudflare Worker)- 作用:这是你的必应站长工具 API 密钥,Worker 需要用它来获得向必应提交 URL 的授权。
- 获取方式:登录必应网站管理员工具,生成并复制你的 API 密钥。
- 配置方法:在你的终端里,进入
bing-submit-worker
目录,然后运行以下命令。它会提示你输入密钥,粘贴进去回车即可。Terminal window npx wrangler secret put BING_API_KEY
-
BING_SUBMIT_WORKER_URL
(用于 GitHub Action)- 作用:这是你部署成功后的 Cloudflare Worker 的访问 URL。GitHub Action 需要知道这个地址,才能把新文件名发送给它。
- 获取方式:当你成功运行
npx wrangler deploy
后,终端会输出你的 Worker URL,通常格式是https://bing-submit-worker.your-account.workers.dev
。 - 配置方法:
- 打开你的 GitHub 仓库页面,进入
Settings
>Secrets and variables
>Actions
。 - 点击
New repository secret
。 - Name:
BING_SUBMIT_WORKER_URL
- Secret: 粘贴你获取到的 Worker URL。
- 打开你的 GitHub 仓库页面,进入
- 结束 🎉 希望这篇教程能帮助你搭建起自己的自动化 SEO 流程,把时间花在更有创造力的事情上,而不是重复性的手动提交。配置完成后,你就可以完全忘记“提交 URL”这件事了,因为系统会为你处理好一切。 如果你觉得这个方案不错,也可以根据这个思路,扩展到其他需要自动化的场景中去。祝大家折腾愉快!😋
附录:最终配置文件
本次修改涉及的核心文件的最终代码。
1. Cloudflare Worker: bing-submit-worker/index.ts
export interface Env { BING_API_KEY: string;}
export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { if (request.method !== 'POST') { return new Response('Expected POST request', { status: 405 }); }
const { files } = await request.json<{ files: string[] }>();
if (!files || !Array.isArray(files)) { return new Response('Missing "files" in request body', { status: 400 }); }
const siteUrl = 'https://www.497995.xyz'; const urls = files.map(file => `${siteUrl}/posts/${file.replace(/\.md$/, '')}/`);
try { const response = await fetch(`https://ssl.bing.com/webmaster/api.svc/json/SubmitUrlbatch?apikey=${env.BING_API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8', }, body: JSON.stringify({ siteUrl, urlList: urls, }), });
const responseData = await response.json();
if (response.ok) { console.log('Successfully submitted URLs to Bing:', responseData); return new Response(JSON.stringify({ success: true, submittedUrls: urls, bingResponse: responseData }), { headers: { 'Content-Type': 'application/json' }, }); } else { console.error('Error submitting URLs to Bing:', responseData); return new Response(JSON.stringify({ success: false, error: responseData }), { status: response.status, headers: { 'Content-Type': 'application/json' }, }); } } catch (error) { console.error('Failed to submit URLs to Bing:', error); return new Response(JSON.stringify({ success: false, error: (error as Error).message }), { status: 500, headers: { 'Content-Type': 'application/json' }, }); } },};
2. Cloudflare Worker 配置: bing-submit-worker/wrangler.toml
name = "bing-submit-worker"main = "index.ts"compatibility_date = "2024-04-05"
[build]command = "pnpm exec tsc"
[build.upload]format = "modules"
[vars]# You need to create a secret for your Bing API key:# wrangler secret put BING_API_KEY
3. GitHub Action 工作流: .github/workflows/bing-submit.yml
name: Submit New Posts to Bing
on: push: branches: - main # Or your default branch paths: - 'src/content/posts/**.md'
jobs: submit-to-bing: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 2 # Fetches the last 2 commits to compare HEAD with the previous commit
- name: Get new files id: get_new_files run: | # Handle the case where before commit might be all zeroes (initial commit) if [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then # For initial commit, get all markdown files in posts directory NEW_FILES=$(find src/content/posts -name "*.md" -type f | sed 's#src/content/posts/##' | jq -R . | jq -s .) else # Get the list of added files in the push NEW_FILES=$(git diff --name-only --diff-filter=A ${{ github.event.before }} ${{ github.event.after }} | grep '^src/content/posts/.*\.md$' | sed 's#src/content/posts/##' | jq -R . | jq -s .) fi
echo "New files detected: $NEW_FILES" echo "files=$NEW_FILES" >> $GITHUB_OUTPUT
# Save to file for debugging echo "$NEW_FILES" > new_files.json
- name: Show files to be submitted run: | echo "Files that will be submitted:" cat new_files.json
- name: Trigger Bing Submission Worker if: steps.get_new_files.outputs.files != '[]' && steps.get_new_files.outputs.files != '' && steps.get_new_files.outputs.files != 'null' run: | echo "Sending files to Bing Submission Worker: ${{ steps.get_new_files.outputs.files }}" curl -X POST "${{ secrets.BING_SUBMIT_WORKER_URL }}" \ -H "Content-Type: application/json" \ -d "{\"files\": ${{ steps.get_new_files.outputs.files }} }"