Notion Webhook来实现Cloudflare Pages自动部署
/ 7分钟阅读
最后更新:目录
1. 代码示例(Cloudflare Pages Functions)
在 Cloudflare Pages 项目的 functions/
目录下,创建 webhook.ts
(或者 .js
),并写入以下代码:
export async function onRequestPost(context) <ruby> try { const req = await context.request.json();
// 处理 Notion 发送的验证 challenge if (req.challenge) { return new Response(JSON.stringify({ challenge: req.challenge }), { headers: { "Content-Type": "application/json" }, }); }
console.log("Received webhook event:", req); return new Response("Webhook received", { status: 200 }); } catch (error) { console.error("Error processing request:", error); return new Response("Internal Server Error", { status: 500 }); }}
2. 部署 Webhook
将 functions/webhook.ts
添加到 Cloudflare Pages 项目后,推送到你的 Git 仓库,Cloudflare Pages 会自动部署。
你的 Webhook URL 将是:
https://your-project.pages.dev/webhook
(your-project.pages.dev
需要替换成你的 Cloudflare Pages 域名)
3. 配置 Webhook
- 在 Notion 开发者控制台(Notion Integrations)中添加你的 Webhook URL(例如
http://your-server.com/webhook
)。 - Notion 发送
challenge
请求后,你的服务器会返回相同的challenge
值,从而完成验证。得到NOTION_VERIFICATION_TOKEN
. 以下是完整的 Cloudflare Worker 代码,实现 Notion Webhook → Cloudflare Pages 自动部署,包含安全验证和详细注释:
// 功能:接收 Notion Webhook 请求 → 验证签名 → 触发 Pages 部署// 需配置环境变量:// 1. NOTION_VERIFICATION_TOKEN : Notion 的验证令牌// 2. CF_DEPLOY_HOOK_URL : Pages 部署挂钩 URL
export async function onRequestPost(context) { const { request, env } = context;
try { const body = await request.text(); const signature = request.headers.get("x-notion-signature"); const verificationToken = env.NOTION_VERIFICATION_TOKEN;
// 环境变量检查 if (!verificationToken <rt>| !env.CF_DEPLOY_HOOK_URL) { console.error("❌ 环境变量未配置"); return new Response(JSON.stringify({ message: "Configuration error" </rt></ruby>), <ruby> status: 500, headers: { "Content-Type": "application/json" } }); }
// 解析请求体 let data; try { data = JSON.parse(body); } catch (err) { return new Response(JSON.stringify({ message: "Invalid JSON" }), { status: 400, headers: { "Content-Type": "application/json" } }); }
// 处理验证请求 if (data.type === "verification") { console.log("✅ 收到验证请求"); return new Response(JSON.stringify({ challenge: data.challenge }), { status: 200, headers: { "Content-Type": "application/json" } }); }
// 验证签名 if (!signature) { return new Response(JSON.stringify({ message: "Missing signature" }), { status: 400, headers: { "Content-Type": "application/json" } }); }
// 计算签名 - 简化版本 const encoder = new TextEncoder(); const key = await crypto.subtle.importKey( "raw", encoder.encode(verificationToken), { name: "HMAC", hash: "SHA-256" }, false, ["sign"] ); const signatureBuffer = await crypto.subtle.sign( "HMAC", key, encoder.encode(body) ); const computedSignature = "sha256=" + Array.from(new Uint8Array(signatureBuffer)) .map(b => b.toString(16).padStart(2, "0")) .join("");
if (signature !== computedSignature) { console.warn("❌ 签名验证失败"); return new Response(JSON.stringify({ message: "Invalid signature" }), { status: 401, headers: { "Content-Type": "application/json" } }); }
// 检查事件类型 if (!data.type <rt>| !['page.', 'block.', 'database.'].some(prefix => data.type.startsWith(prefix))) { console.warn("⚠️ 未知的事件类型:", data.type); return new Response(JSON.stringify({ message: "Acknowledged" </rt></ruby>), { status: 200, headers: { "Content-Type": "application/json" } }); }
// 触发部署 console.log("🚀 触发 Cloudflare Pages 部署"); const deployResponse = await fetch(env.CF_DEPLOY_HOOK_URL, { method: "POST" });
if (!deployResponse.ok) { throw new Error(`部署触发失败: ${await deployResponse.text()}`); }
return new Response(JSON.stringify({ message: "Success" }), { status: 200, headers: { "Content-Type": "application/json" } });
} catch (error) { console.error("💥 处理出错:", error); return new Response(JSON.stringify({ message: "Internal server error", error: error.message }), { status: 500, headers: { "Content-Type": "application/json" } }); }}
4. 配置环境变量
在 Cloudflare Worker 的 Settings → Variables 中配置:
Column 1 | Column 2 | Column 3 |
---|---|---|
变量名 | 值示例 | 获取方式 |
NOTION_VERIFICATION_TOKEN | secret_xxxx | Notion Webhook 首次验证请求中的 verification_token |
CF_DEPLOY_HOOK_URL | https://api.cloudflare.com/.../trigger?key=xxxx | Pages 项目 → Deployment Hooks 创建 |