skip to content
Logo 碧海明珠

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 1Column 2Column 3
变量名值示例获取方式
NOTION_VERIFICATION_TOKENsecret_xxxxNotion Webhook 首次验证请求中的 verification_token
CF_DEPLOY_HOOK_URLhttps://api.cloudflare.com/.../trigger?key=xxxxPages 项目 → Deployment Hooks 创建