Cloudflare Workers — AI时代0元开张:30分钟用Cloudflare部署产品等待列表

很多人的产品,死在了「还没找到服务器」里。

这句话我越想越觉得扎心。

不是死在没人买。不是死在竞争太激烈。甚至不是死在技术不够牛逼。而是死在第一步。

想验证一个想法,先要学 AWS,配 Nginx,搞 Docker,买服务器,配数据库,研究 HTTPS。还没开始写产品,人已经凉了一半。

这事儿对很多普通人来说,太真实了。你脑子里突然冒出一个想法。想做个小工具。想做个 AI 应用。想做个副业页面。想先看看有没有人感兴趣。然后你打开教程。第一行,先准备一台服务器。尼玛。热情瞬间熄火。

但这篇东西真正让我有「原来如此」感觉的地方在于,它把产品验证这件事,从「先搭一整套基础设施」,改成了「先上一个等待列表」。

产品还没做完。没关系。先上线一个页面。让用户留下邮箱。有人留,继续做。没人留,换方向。

这才是普通人做产品最应该理解的逻辑。不是先憋三个月做一个完整产品。而是先把一个最小信号丢到真实世界里。看世界理不理你。

更骚的是,这套东西可以 30 分钟部署到全球。成本 0 美元。用的是 Cloudflare Workers 和 Pages。

Workers 是 Cloudflare 的无服务器计算平台。你写一段 JavaScript 或 TypeScript, wrangler deploy 一行命令,代码就能跑在全球 335 个城市的服务器上。没有服务器要管。没有 Nginx 要配。没有 Express 必须写。没有「我先去买台云服务器」这种古早仪式感。

Pages 是 Cloudflare 的前端部署平台,对标 Vercel。连接 GitHub,每次 push 自动构建部署。前端页面归 Pages。后端 API 归 Pages Functions,也就是 Workers。前后端放在一个项目里。一次部署。同时上线。

这一下就很「卧槽这都行」。因为你会发现,所谓产品上线,原来可以不是一个庞大的工程。它可以就是一个邮箱框。一个 API。一个 SQLite 数据库。一个部署命令。然后你的想法,就真的站到了互联网上。

这和普通人有什么关系?关系太大了。

  • 如果你是自媒体人,你可以先做一个资料库等待列表。
  • 如果你是设计师,你可以先做一个作品集工具等待列表。
  • 如果你是程序员,你可以先做一个开源工具的早鸟名单。
  • 如果你是老师,你可以先做一个课程报名页。
  • 如果你只是有一个很小的副业想法,你也可以先别做完整产品。先让真实用户留下邮箱。

这就是 最低成本的市场测谎仪 。嘴上说想要的人很多。愿意留下邮箱的人,少很多。愿意付钱的人,更少。但你必须先走到第一步。

下面这段就是完整实操。照着做,你会得到一个真正能跑的等待列表。

动手,30 分钟部署一个产品等待列表

这是每个一人公司都会用到的东西,产品还没做完,先把等待列表上线,收集感兴趣的用户邮箱。我们要做的东西很简单。一个页面,用户输入邮箱点提交。后端 API,把邮箱存进数据库。完全运行在 Cloudflare,0 美元。

第一步,安装工具,创建项目,5 分钟。

安装 Wrangler,Cloudflare 命令行工具,并登录。

npm install -g wrangler
wrangler login

浏览器弹出授权页面,点允许。创建项目。

npm create cloudflare@latest waitlist -- --type hello-world --ts --no-git --no-deploy
cd waitlist

项目结构是这样。

waitlist/
src/
  index.ts       ← 这里写后端 API
public/          ← 这里放前端页面
wrangler.jsonc

这一步的认知点在这里。你不是在「买服务器」。你是在创建一个可以同时放前端和后端的小产品壳子。原来如此。以前我们以为上线一个产品要先搞一台机器。现在其实是先搞一个项目结构。

第二步,创建数据库,3 分钟。

D1 是 Cloudflare 的 SQLite 数据库,免费 5GB。

wrangler d1 create waitlist-db

命令返回一个 database_id ,把它填进 wrangler.jsonc

"d1_databases": [
  {
    "binding": "waitlist_db",
    "database_name": "waitlist-db",
    "database_id": "这里填你的 id"
  }
],
"assets": {
  "directory": "./public/",
  "run_worker_first": ["/api/*"]
}

建表。

wrangler d1 execute waitlist-db --command 
"CREATE TABLE emails (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT UNIQUE NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP);"

这里也很有意思。你不是单独去买数据库。也不是去装 MySQL。就是直接在 Cloudflare 里创建一个 SQLite 数据库。邮箱这种等待列表数据,本来就不复杂。一个 emails 表就够了。id,email,created_at。就这三个字段。别把事情想复杂。

第三步,写后端 API,10 分钟。

src/index.ts 里写 Worker 入口。

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const headers = {
      "Content-Type": "application/json",
      "Access-Control-Allow-Origin": "*",
    };

    if (request.method === "OPTIONS") {
      return new Response(null, { headers });
    }

    if (url.pathname === "/api/subscribe" && request.method === "POST") {
      try {
        const { email } = await request.json<{ email: string }>();

        if (!email || !email.includes("@")) {
          return Response.json({ error: "邮箱格式不对" }, { status: 400, headers });
        }

        await env.waitlist_db.prepare(
          "INSERT INTO emails (email) VALUES (?)"
        ).bind(email).run();

        return Response.json({ message: "成功加入等待列表!" }, { headers });

      } catch (e: any) {
        if (e.message?.includes("UNIQUE constraint")) {
          return Response.json({ error: "这个邮箱已经登记过了" }, { status: 409, headers });
        }
        return Response.json({ error: "出错了,请重试" }, { status: 500, headers });
      }
    }

    return new Response("Not Found", { status: 404 });
  },
} satisfies ExportedHandler<Env>;

run_worker_first 配置让 /api/* 路由走 Worker,其余路由自动走 public/ 静态文件。不需要配路由框架。不需要写 Express。这就是「卧槽这都行」的地方。以前后端要起服务,要监听端口,要部署进程,要守护服务。现在这里就是一个 fetch 函数。请求来了,它处理一下。邮箱合法,就写进 D1。邮箱重复,就返回「这个邮箱已经登记过了」。出错了,就返回「请重试」。一个等待列表的后端,就这么没了。

第四步,写前端页面,5 分钟。

public/ 目录下新建 index.html

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>即将上线</title>
<style>
body {
  font-family: -apple-system, sans-serif;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0;
  background: #0f0f0f;
  color: #fff;
}
.container { text-align: center; max-width: 480px; padding: 2rem; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #888; margin-bottom: 2rem; }
.form { display: flex; gap: 0.5rem; }
input {
  flex: 1;
  padding: 0.75rem 1rem;
  border: 1px solid #333;
  border-radius: 8px;
  background: #1a1a1a;
  color: #fff;
  font-size: 1rem;
}
button {
  padding: 0.75rem 1.5rem;
  background: #fff;
  color: #000;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  cursor: pointer;
  font-weight: 600;
}
#msg { margin-top: 1rem; min-height: 1.5rem; color: #888; }
</style>
</head>
<body>
<div class="container">
<h1>即将上线</h1>
<p>留下邮箱,第一时间通知你。</p>
<div class="form">
<input type="email" id="email" placeholder="your@email.com">
<button onclick="subscribe()">通知我</button>
</div>
<div id="msg"></div>
</div>
<script>
async function subscribe() {
  const email = document.getElementById("email").value;
  const msg = document.getElementById("msg");

  if (!email) { msg.textContent = "请输入邮箱"; return; }

  msg.textContent = "提交中…";

  const res = await fetch("/api/subscribe", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email }),
  });

  const data = await res.json();
  msg.textContent = data.message || data.error;
  if (res.ok) document.getElementById("email").value = "";
}
</script>
</body>
</html>

这个页面朴素到不能再朴素。一个标题。一句话。一个输入框。一个按钮。但这就够了。因为等待列表不是用来炫技的。它只负责回答一个问题。有没有人愿意留下邮箱?这就是它和普通人的关系。你不是要一次性做出一个完美产品。你只是要做一个足够真实的入口,让用户用行动告诉你,这个东西有没有继续做的必要。

第五步,本地测试,2 分钟。

wrangler dev

打开 http://localhost:8787 ,填一个邮箱,点「通知我」。检查数据库有没有写进去。

wrangler d1 execute waitlist-db --command "SELECT * FROM emails;"

这一步很关键。不要跳过测试。很多人做产品容易犯一个问题,觉得页面能打开就完事了。但等待列表真正的核心,是邮箱有没有进数据库。页面只是表皮。数据才是资产。

第六步,部署上线,3 分钟。

wrangler deploy

两分钟后,你拿到一个地址。

https://waitlist.<your-subdomain>.workers.dev

全球可访问。自动 HTTPS。0 美元。以后每次 git push ,自动重新部署。

这一下就很反直觉。因为你会发现,上线这件事本身,居然已经不再是一个大工程了。过去你要告诉自己,等我准备好了再上线。现在不是。现在你应该反过来问自己。我为什么还不上线?

查看收集到的邮箱,随时可以查。

wrangler d1 execute waitlist-db --command "SELECT * FROM emails ORDER BY created_at DESC;"

或者在 Cloudflare 控制台,D1,你的数据库,直接跑 SQL。

这套方案能撑多少用户?免费额度,每天 10 万次 Workers 请求,加每天 10 万行 D1 写入。产品没上线之前,用等待列表收邮箱,完全免费。

这就是最让人震惊的地方。不是它省了多少钱。而是它把「试错」这件事变便宜了。以前你验证一个想法,脑子里默认成本很高。要花钱。要求人。要组队。要部署。要维护。所以你会拖。拖到最后,想法自己死了。

但现在,你可以先做一个等待列表。你有一个 AI 工具想法,先收邮箱。你想做一个课程,先收邮箱。你想做一个资料库,先收邮箱。你想做一个小 SaaS,先收邮箱。你想做一个社群,先收邮箱。如果没人留邮箱,说明这个想法可能没有你想的那么重要。如果有人留邮箱,你再继续往下做。原来如此。

等待列表不是一个页面。它是普通人的低成本验证器。你不用一开始就证明自己能做出完整产品。你只需要证明,有人愿意等它。

我觉得这里最值得普通人记住的,不是 Cloudflare,也不是 Workers,也不是 D1。而是一个动作。先把想法放到真实世界里。

别一直在脑子里优化。别一直在 Notion /飞书里规划。别一直等准备好了。很多时候,你缺的不是更完整的计划。你缺的是一个邮箱框。一个按钮。一个可以被别人点击的入口。世界不会因为你想了很多奖励你。世界只会回应你丢出去的东西。以前,把东西丢出去很贵。现在,30 分钟。0 美元。这才是最值得兴奋的地方。

FAQ

这个等待列表方案需要花钱吗?

完全不需要。Cloudflare Workers 和 D1 数据库提供慷慨的免费额度,每天 10 万次请求和 10 万行写入,对验证阶段的产品完全够用。

我不会写代码,能用这个方案吗?

文章提供了完整的代码和命令行步骤,复制粘贴就能跑。如果你完全零基础,建议先跟着教程走一遍,遇到问题可以搜索 Cloudflare 官方文档。

等待列表收集的邮箱数据安全吗?

数据存储在 Cloudflare D1 中,受 Cloudflare 安全体系保护。你可以随时通过命令行或控制台查看和管理数据,建议遵守隐私法规并告知用户数据用途。