深入理解两个产品的区别,选择最适合的解决方案

September, 22nd 2025 19 min read

深入理解两个产品的区别,选择最适合的解决方案

目录


核心概念对比

Cloudflare Workers

定位:无服务器计算平台,运行后端逻辑 本质:JavaScript/TypeScript 运行时,处理 HTTP 请求

Cloudflare Pages

定位:JAMstack 平台,托管静态网站 本质:静态文件托管 + Pages Functions(基于 Workers)

一句话区别

  • Workers:你写的是一个完整的服务器应用
  • Pages:你部署的是一个网站(可选添加后端功能)

技术架构差异

Workers 架构

plaintext
123
      请求 → Workers Runtime → 你的代码处理一切 → 响应
         ↓
    可以返回HTML、JSON、二进制等任何内容
    
javascript
123456789101112131415161718192021222324
      // Workers - 完全控制请求处理
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    
    // 你需要自己处理所有路由
    if (url.pathname === '/') {
      return new Response('<h1>Home</h1>', {
        headers: { 'Content-Type': 'text/html' }
      });
    }
    
    if (url.pathname === '/api/data') {
      return Response.json({ data: 'value' });
    }
    
    if (url.pathname.startsWith('/static/')) {
      // 需要自己处理静态文件
      return fetch(`https://cdn.example.com${url.pathname}`);
    }
    
    return new Response('Not Found', { status: 404 });
  }
}
    

Pages 架构

plaintext
1234567
      请求 → Pages 路由系统
         ↓
    静态文件? → 直接返回文件
         ↓
    /api/* 或 Functions? → Pages Functions 处理
         ↓
    都不是? → 返回 404 或 index.html(SPA)
    
javascript
123456789101112
      // Pages Functions - functions/api/hello.js
// 自动处理 /api/hello 路由
export async function onRequest(context) {
  return Response.json({ message: 'Hello' });
}

// 静态文件自动托管,无需编写代码
// public/
//   ├── index.html      → /
//   ├── about.html      → /about
//   ├── css/style.css   → /css/style.css
//   └── js/app.js       → /js/app.js
    

功能特性对比

详细功能对比表

功能特性WorkersPages说明
静态文件托管❌ 需手动实现✅ 原生支持Pages 自动处理静态资源
自动路由❌ 手动编写✅ 文件系统路由Pages 基于文件结构自动路由
Git 集成❌ 需 CI/CD✅ 自动部署Pages 支持 GitHub/GitLab 集成
预览环境⚠️ 需配置✅ 每个 PR 自动Pages 为每个 PR 创建预览 URL
自定义域名✅ 支持✅ 支持都支持自定义域名
API 端点✅ 完全控制✅ Pages FunctionsWorkers 更灵活
WebSocket✅ 支持⚠️ 仅 FunctionsWorkers 原生支持
定时任务✅ Cron Triggers❌ 不支持只有 Workers 支持
队列消费✅ Queue Consumer❌ 不支持只有 Workers 支持
Durable Objects✅ 支持⚠️ 仅 FunctionsWorkers 完整支持
中间件✅ 自己实现✅ 内置支持Pages Functions 有中间件链
重定向规则❌ 代码实现✅ _redirects 文件Pages 支持配置文件
请求头规则❌ 代码实现✅ _headers 文件Pages 支持配置文件
构建系统❌ 无✅ 内置Pages 支持各种框架构建
环境变量✅ wrangler.toml✅ 仪表板配置Pages 更易管理
分析✅ Workers Analytics✅ Web AnalyticsPages 有更丰富的分析

Workers 独有功能

javascript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
      // 1. Cron Triggers - 定时任务
export default {
  async scheduled(event, env, ctx) {
    // 每小时执行一次
    await cleanupOldData(env);
  },
  
  async fetch(request, env, ctx) {
    // 常规 HTTP 处理
  }
}

// wrangler.toml
// [triggers]
// crons = ["0 * * * *"]

// 2. Queue Consumer - 消息队列
export default {
  async queue(batch, env, ctx) {
    for (const message of batch.messages) {
      await processMessage(message);
      message.ack();
    }
  }
}

// 3. TCP Sockets (beta)
export default {
  async fetch(request, env, ctx) {
    const socket = new Socket({
      address: 'tcp.example.com',
      port: 8080
    });
    
    await socket.connect();
    await socket.write('Hello TCP');
    const response = await socket.read();
    
    return new Response(response);
  }
}

// 4. 完全自定义路由
export default {
  async fetch(request, env, ctx) {
    const router = new Router();
    
    router.get('/users/:id', async ({ params }) => {
      return Response.json({ userId: params.id });
    });
    
    router.post('/api/*', async (request) => {
      // 处理所有 API 请求
    });
    
    return router.handle(request);
  }
}
    

Pages 独有功能

javascript
123456789101112131415161718192021222324252627282930313233343536373839404142434445
      // 1. 文件系统路由
// functions/api/users/[id].js
export function onRequestGet({ params }) {
  return Response.json({ userId: params.id });
}

// 2. 中间件链
// functions/_middleware.js
export async function onRequest(context) {
  const { request, next } = context;
  
  // 认证检查
  if (!request.headers.get('Authorization')) {
    return new Response('Unauthorized', { status: 401 });
  }
  
  // 继续处理
  const response = await next();
  
  // 添加响应头
  response.headers.set('X-Custom', 'value');
  
  return response;
}

// 3. 静态文件配置
// _redirects
/old-page /new-page 301
/api/* https://api.backend.com/:splat 200

// _headers
/static/*
  Cache-Control: public, max-age=31536000
  
/*.js
  Content-Type: application/javascript
  X-Content-Type-Options: nosniff

// 4. 框架预设
// 自动识别并构建:
// - React (Create React App, Next.js)
// - Vue (Vue CLI, Nuxt)
// - Angular
// - Svelte (SvelteKit)
// - Astro, Gatsby, Hugo, Jekyll, 等等
    

使用场景分析

Workers 最适合的场景

1. 纯 API 服务

javascript
1234567891011121314
      // RESTful API 服务
export default {
  async fetch(request, env) {
    const api = new API(env);
    
    return api
      .route('GET', '/users', getAllUsers)
      .route('POST', '/users', createUser)
      .route('GET', '/users/:id', getUser)
      .route('PUT', '/users/:id', updateUser)
      .route('DELETE', '/users/:id', deleteUser)
      .handle(request);
  }
}
    

为什么选 Workers

  • 不需要静态文件托管
  • 需要完全控制路由
  • 需要高性能 API

2. 微服务/中间件

javascript
1234567891011121314151617181920
      // 认证网关
export default {
  async fetch(request, env) {
    // 验证 JWT
    const token = request.headers.get('Authorization');
    const valid = await verifyJWT(token, env.JWT_SECRET);
    
    if (!valid) {
      return new Response('Unauthorized', { status: 401 });
    }
    
    // 代理到后端
    return fetch('https://backend.internal' + request.url, {
      headers: {
        ...request.headers,
        'X-User-Id': getUserId(token)
      }
    });
  }
}
    

为什么选 Workers

  • 作为独立服务运行
  • 不需要前端界面
  • 需要处理所有类型的请求

3. 实时应用

javascript
123456789101112131415161718
      // WebSocket 服务器
export default {
  async fetch(request, env) {
    if (request.headers.get('Upgrade') === 'websocket') {
      const pair = new WebSocketPair();
      const [client, server] = Object.values(pair);
      
      handleWebSocket(server, env);
      
      return new Response(null, {
        status: 101,
        webSocket: client
      });
    }
    
    return new Response('WebSocket server');
  }
}
    

为什么选 Workers

  • 需要 WebSocket 支持
  • 需要持久连接
  • 需要实时通信

4. 定时任务/后台处理

javascript
12345678910111213141516171819
      // 数据同步服务
export default {
  async scheduled(event, env) {
    // 每天凌晨 2 点执行
    const data = await fetchExternalData();
    await env.DB.prepare('INSERT INTO ...').run();
    
    // 发送报告
    await sendEmail(env);
  },
  
  async queue(batch, env) {
    // 处理异步任务
    for (const message of batch.messages) {
      await processJob(message.body);
      message.ack();
    }
  }
}
    

为什么选 Workers

  • 需要 Cron 触发器
  • 需要队列处理
  • 纯后端任务

Pages 最适合的场景

1. 静态网站 + API

plaintext
1234567891011
      my-blog/
├── public/
│   ├── index.html
│   ├── blog/
│   │   ├── post1.html
│   │   └── post2.html
│   └── css/style.css
└── functions/
    └── api/
        ├── posts.js       # API: 获取文章列表
        └── comments.js    # API: 评论功能
    

为什么选 Pages

  • 主要是静态内容
  • 少量 API 需求
  • 需要 CDN 加速

2. SPA 应用(React/Vue/Angular)

javascript
123456789101112131415
      // React 应用 + API
// 自动构建和部署

// functions/api/auth.js
export async function onRequestPost({ request, env }) {
  const { username, password } = await request.json();
  const user = await authenticate(username, password, env);
  
  if (user) {
    const token = await generateJWT(user, env);
    return Response.json({ token });
  }
  
  return new Response('Invalid credentials', { status: 401 });
}
    

为什么选 Pages

  • 前端框架自动构建
  • Git 集成自动部署
  • 预览环境支持

3. 文档网站

plaintext
1234567891011121314
      docs-site/
├── public/
│   ├── index.html
│   ├── docs/
│   │   ├── getting-started.html
│   │   ├── api-reference.html
│   │   └── guides/
│   └── search.json
├── functions/
│   └── api/
│       └── search.js  # 搜索 API
└── _redirects         # 重定向规则
    /v1/* /docs/v1/:splat 301
    /latest/* /docs/v2/:splat 302
    

为什么选 Pages

  • 内容为主
  • 需要良好的 SEO
  • 简单的搜索功能

4. 营销网站/落地页

html
1234567891011121314151617181920
      <!-- 营销网站with表单处理 -->
<!-- public/index.html -->
<form action="/api/subscribe" method="POST">
  <input name="email" type="email" required>
  <button>订阅</button>
</form>

<!-- functions/api/subscribe.js -->
export async function onRequestPost({ request, env }) {
  const formData = await request.formData();
  const email = formData.get('email');
  
  // 保存到数据库
  await env.DB.prepare('INSERT INTO subscribers...').run();
  
  // 发送欢迎邮件
  await sendWelcomeEmail(email, env);
  
  return Response.redirect('/thank-you');
}
    

为什么选 Pages

  • 静态内容为主
  • 简单的表单处理
  • 需要快速迭代

性能和限制对比

性能指标

指标WorkersPages说明
冷启动< 5ms< 5ms (Functions)静态文件无冷启动
静态文件N/A< 10msPages 针对静态优化
全球延迟< 50ms< 30ms (静态)Pages 静态文件更快
并发请求无限制无限制都可自动扩展
CPU 时间10ms-30s10ms-30s付费计划可更高

限制对比

限制项Workers FreeWorkers PaidPages FreePages Paid
请求/天100,000无限制无限制无限制
请求/月1000万按量付费无限制无限制
CPU 时间10ms30s10ms30s
内存128MB128MB128MB128MB
脚本大小1MB10MB1MB10MB
环境变量64个64个64个64个
KV 操作1000/天按量付费1000/天按量付费
构建时间N/AN/A20分钟20分钟
并发构建N/AN/A15
部署/月无限制无限制5005000
带宽无限制无限制无限制无限制

文件大小限制

Workers

  • 压缩后 1MB(免费)
  • 压缩后 10MB(付费)
  • 单个文件最大 25MB(使用 R2)

Pages

  • 单个文件最大 25MB
  • 总计最多 20,000 个文件
  • 总大小无限制

成本分析

Workers 成本结构

plaintext
123456789101112
      免费额度:
- 每天 100,000 请求
- 每月 1000 万请求

付费($5/月起):
- 前 1000 万请求包含在内
- 超出部分 $0.50/百万请求
- CPU 时间额外计费

示例:
- 月 5000 万请求
- 成本:$5 + (40 * $0.50) = $25
    

Pages 成本结构

plaintext
1234567891011121314
      免费额度:
- 无限请求(静态文件)
- 每月 500 次构建
- 1 个并发构建

付费($20/月起):
- 无限请求
- 每月 5000 次构建
- 5 个并发构建
- Pages Functions 按 Workers 计费

示例:
- 静态网站 + 少量 API
- 成本:$0(免费层足够)
    

成本对比示例

场景 1:博客网站(月 100 万访问)

  • Workers: $5/月(需要处理所有请求)
  • Pages: $0/月(静态文件免费)
  • 推荐: Pages ✅

场景 2:API 服务(月 5000 万请求)

  • Workers: $25/月
  • Pages Functions: $25/月(相同)
  • 推荐: Workers ✅(更适合纯 API)

场景 3:SaaS 应用(前端+API)

  • Workers: $25/月(处理一切)
  • Pages: $20/月(构建)+ $5(Functions)= $25/月
  • 推荐: Pages ✅(更好的开发体验)

选择决策树

mermaid
1234567891011121314151617181920212223
      graph TD
    A[开始] --> B{需要静态文件托管?}
    
    B -->|是| C{API 需求多吗?}
    B -->|否| D{是纯 API 服务?}
    
    C -->|多| E{需要构建系统?}
    C -->|少| F[Pages ✅]
    
    D -->|是| G[Workers ✅]
    D -->|否| H{需要定时任务?}
    
    E -->|是| I[Pages ✅]
    E -->|否| J{团队熟悉度?}
    
    H -->|是| K[Workers ✅]
    H -->|否| L{需要 WebSocket?}
    
    J -->|前端团队| M[Pages ✅]
    J -->|后端团队| N[Workers ✅]
    
    L -->|是| O[Workers ✅]
    L -->|否| P[两者皆可]
    

快速决策指南

选择 Workers 如果

  • ✅ 纯 API 服务
  • ✅ 需要定时任务
  • ✅ 需要队列处理
  • ✅ 需要 WebSocket
  • ✅ 微服务架构
  • ✅ 复杂的路由逻辑
  • ✅ 需要完全控制

选择 Pages 如果

  • ✅ 静态网站为主
  • ✅ SPA 应用
  • ✅ 需要 Git 集成
  • ✅ 需要预览环境
  • ✅ 团队习惯 JAMstack
  • ✅ 内容网站
  • ✅ 需要快速上线

混合使用策略

策略 1:Pages 前端 + Workers API

plaintext
1234567
      架构:
┌─────────────┐     ┌──────────────┐
│   Pages     │────▶│   Workers    │
│  (前端SPA)  │     │  (API后端)   │
└─────────────┘     └──────────────┘
       ↓                    ↓
   静态文件CDN          业务逻辑处理
    

实现方式

javascript
12345678910111213141516171819202122
      // Pages - 前端应用
// public/app.js
const API_URL = 'https://api.example.workers.dev';

async function fetchData() {
  const response = await fetch(`${API_URL}/data`);
  return response.json();
}

// Workers - API 后端
export default {
  async fetch(request, env) {
    // 设置 CORS
    const headers = {
      'Access-Control-Allow-Origin': 'https://app.example.pages.dev',
      'Content-Type': 'application/json'
    };
    
    // 处理 API 请求
    return Response.json({ data: 'value' }, { headers });
  }
}
    

策略 2:Workers 路由 + Pages 内容

javascript
1234567891011121314
      // Workers 作为主入口,代理到 Pages
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    // API 请求自己处理
    if (url.pathname.startsWith('/api/')) {
      return handleAPI(request, env);
    }
    
    // 静态内容代理到 Pages
    return fetch(`https://content.pages.dev${url.pathname}`);
  }
}
    

策略 3:多个 Pages 项目组合

plaintext
12345
      主站(Pages): example.com
├── 博客(Pages): blog.example.com
├── 文档(Pages): docs.example.com
├── API(Workers): api.example.com
└── 管理后台(Pages): admin.example.com
    

实战案例

案例 1:电商网站

需求分析

  • 产品展示页面(静态)
  • 购物车(动态)
  • 用户认证
  • 订单处理
  • 支付集成

推荐方案:Pages + Functions

plaintext
12345678910111213
      ecommerce-site/
├── public/
│   ├── index.html         # 首页
│   ├── products/          # 产品页面
│   └── assets/            # 静态资源
├── functions/
│   ├── api/
│   │   ├── auth.js        # 认证
│   │   ├── cart.js        # 购物车
│   │   ├── orders.js      # 订单
│   │   └── payment.js     # 支付
│   └── _middleware.js     # 认证中间件
└── wrangler.toml
    

为什么选 Pages

  • 产品页面可以静态生成
  • Functions 足够处理 API
  • Git 集成方便部署

案例 2:实时协作工具

需求分析

  • WebSocket 连接
  • 实时数据同步
  • 用户状态管理
  • 持久化存储

推荐方案:Workers + Durable Objects

javascript
1234567891011121314151617181920212223242526272829
      // Workers 实现
export class CollaborationRoom {
  constructor(state, env) {
    this.state = state;
    this.sessions = [];
  }
  
  async fetch(request) {
    // WebSocket 处理
    const pair = new WebSocketPair();
    this.handleSession(pair[1]);
    
    return new Response(null, {
      status: 101,
      webSocket: pair[0]
    });
  }
  
  handleSession(webSocket) {
    // 实时协作逻辑
    webSocket.accept();
    this.sessions.push(webSocket);
    
    webSocket.addEventListener('message', event => {
      // 广播给其他用户
      this.broadcast(event.data, webSocket);
    });
  }
}
    

为什么选 Workers

  • 需要 WebSocket
  • 需要 Durable Objects
  • 实时性要求高

案例 3:企业官网

需求分析

  • 公司介绍
  • 产品展示
  • 新闻博客
  • 联系表单
  • 多语言支持

推荐方案:Pages

plaintext
123456789101112
      corporate-site/
├── public/
│   ├── index.html
│   ├── about/
│   ├── products/
│   ├── blog/
│   └── locales/         # 多语言
├── functions/
│   └── api/
│       └── contact.js    # 表单处理
├── _redirects            # URL 重定向
└── _headers              # 缓存策略
    

为什么选 Pages

  • 内容为主
  • 更新不频繁
  • SEO 重要
  • 简单的表单处理

案例 4:API 网关

需求分析

  • 请求路由
  • 认证授权
  • 限流
  • 日志记录
  • 请求转换

推荐方案:Workers

javascript
1234567891011121314151617181920212223242526272829
      export default {
  async fetch(request, env, ctx) {
    // 限流检查
    const rateLimitOk = await checkRateLimit(request, env);
    if (!rateLimitOk) {
      return new Response('Too Many Requests', { status: 429 });
    }
    
    // 认证
    const auth = await authenticate(request, env);
    if (!auth.valid) {
      return new Response('Unauthorized', { status: 401 });
    }
    
    // 路由到后端服务
    const backend = selectBackend(request.url);
    const response = await fetch(backend, {
      headers: {
        ...request.headers,
        'X-User-Id': auth.userId
      }
    });
    
    // 记录日志
    ctx.waitUntil(logRequest(request, response, env));
    
    return response;
  }
}
    

为什么选 Workers

  • 纯 API 服务
  • 需要灵活路由
  • 中间件功能
  • 不需要静态文件

迁移指南

从 Workers 迁移到 Pages

javascript
12345678910111213141516171819202122232425
      // Workers 原代码
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    if (url.pathname === '/') {
      return new Response(HTML_CONTENT, {
        headers: { 'Content-Type': 'text/html' }
      });
    }
    
    if (url.pathname === '/api/data') {
      return Response.json(await getData(env));
    }
    
    return new Response('Not Found', { status: 404 });
  }
}

// 迁移到 Pages
// 1. 将 HTML 放到 public/index.html
// 2. 创建 functions/api/data.js
export async function onRequest({ env }) {
  return Response.json(await getData(env));
}
    

从 Pages 迁移到 Workers

javascript
12345678910111213141516171819202122
      // Pages Functions
// functions/api/users/[id].js
export async function onRequestGet({ params, env }) {
  const user = await getUser(params.id, env);
  return Response.json(user);
}

// 迁移到 Workers
import { Router } from 'itty-router';

const router = Router();

router.get('/api/users/:id', async ({ params }, env) => {
  const user = await getUser(params.id, env);
  return Response.json(user);
});

export default {
  async fetch(request, env) {
    return router.handle(request, env);
  }
}
    

总结和建议

核心原则

  1. 内容驱动选 Pages

    • 静态内容多
    • SEO 重要
    • 需要 CDN
  2. 逻辑驱动选 Workers

    • API 为主
    • 复杂业务逻辑
    • 需要后台任务
  3. 开发体验优先选 Pages

    • Git 集成
    • 自动部署
    • 预览环境
  4. 性能要求高选 Workers

    • 完全控制
    • 自定义优化
    • 特殊需求

最终建议

新项目默认选择策略

  1. 先考虑 Pages(开发体验好)
  2. 如果 Pages 不满足,再选 Workers
  3. 复杂项目可以混合使用

团队因素

  • 前端团队 → Pages
  • 后端团队 → Workers
  • 全栈团队 → 根据项目选择

未来趋势

  • Pages 和 Workers 功能越来越接近
  • Pages Functions 基本等同于 Workers
  • 选择更多基于开发体验而非功能差异

快速参考

Workers 项目初始化

bash
12345
      npm create cloudflare@latest my-worker
# 选择 "Hello World" Worker
cd my-worker
npm run dev
npm run deploy
    

Pages 项目初始化

bash
1234567891011
      npm create cloudflare@latest my-site
# 选择框架或 "None"
cd my-site
npm run dev
npm run build
npm run deploy

# 或通过 Git
# 1. 推送到 GitHub
# 2. 在 Cloudflare Dashboard 连接仓库
# 3. 自动部署
    

配置文件对比

Workers (wrangler.toml)

toml
123456789
      name = "my-worker"
main = "src/index.js"
compatibility_date = "2024-01-01"

[env.production]
vars = { API_KEY = "secret" }
kv_namespaces = [
  { binding = "KV", id = "xxx" }
]
    

Pages (无需配置文件)

  • 环境变量:Dashboard 设置
  • 构建命令:Dashboard 设置
  • Functions:自动识别 functions/ 目录

选择 Workers 还是 Pages,关键是理解你的需求核心是内容还是逻辑。