少维护一个服务,多一份安心。用cloudflare替换 n8n 上的一个webhook服务
如果你在使用自动化工具(n8n/Make/Zapier等),尽量别把核心 Webhook 节点放在会自动“休眠”的平台上(比如免费版 Zeabur/Render)。 我刚踩坑:几天没请求服务就停了,整个自动化的入口断掉。🤦♂️ 终极解法:用 Cloudflare Workers 做第一层 Webhook 接收点。 写几十行 JS 接收请求、解析数据,直接存进 R2,不仅零服务器成本,而且 24h 永远在线。简单的管道任务,有时候写代码反而是最稳健的方案。☁️
ZEABUR踩的坑
几天没打开 Zeabur,发现部署在上面的 n8n 居然因为“不活跃”被自动暂停了...
刚好有个重要的数据(Notion 传图片)急着跑。
一生气,直接写了个 Cloudflare Worker 平替原先的 n8n webhook 节点,图片直连 R2。
永远在线,拒绝“休眠应用”
零冷启动焦虑
极度轻量,免费额度根本用不完
大家现在搞数据自动化,首选什么方案?老老实实买 VPS 还是只用 Serverless?
plain text:
如果你在使用自动化工具(n8n/Make/Zapier等),尽量别把核心 Webhook 节点放在会自动“休眠”的平台上(比如免费版 Zeabur/Render)。
我刚踩坑:几天没请求服务就停了,整个自动化的入口断掉。🤦♂️
终极解法:用 Cloudflare Workers 做第一层 Webhook 接收点。
写几十行 JS 接收请求、解析数据,直接存进 R2,不仅零服务器成本,而且 24h 永远在线。简单的管道任务,有时候写代码反而是最稳健的方案。☁️plain text:
少维护一个服务,多一份安心。
无代码/低代码确实快,但遇到这种纯接口对接的事,手撸几十行 Serverless 代码反而是最高效、最稳健的方式。同意吗?👇
新的worker代码
javascript:
// worker.js
var worker_default = {
async fetch(request, env, ctx) {
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
try {
const body = await request.json();
const picurl = body.picurl;
if (!picurl) {
return new Response("Missing picurl in request body", { status: 400 });
}
const url = new URL(picurl);
const pathname = url.pathname;
const filename = decodeURIComponent(pathname.split("/").pop()) || `notion_image_${Date.now()}.jpg`;
const imageResponse = await fetch(picurl);
if (!imageResponse.ok) {
return new Response(`Failed to fetch image from URL: ${imageResponse.statusText}`, { status: 500 });
}
const imageBuffer = await imageResponse.arrayBuffer();
const r2Key = `x2r2/${filename}`;
if (!env.R2_BUCKET) {
return new Response("R2 bucket binding (R2_BUCKET) is not configured in worker", { status: 500 });
}
await env.R2_BUCKET.put(r2Key, imageBuffer, {
httpMetadata: {
contentType: imageResponse.headers.get("content-type") || "application/octet-stream"
}
});
return new Response(JSON.stringify({
success: true,
message: "Image successfully saved to R2",
filename,
key: r2Key
}), {
status: 200,
headers: {
"Content-Type": "application/json"
}
});
} catch (error) {
return new Response(`Error processing request: ${error.message}`, { status: 500 });
}
}
};
export {
worker_default as default
};
//# sourceMappingURL=worker.js.map
