Cloudflare

Cloudflare Workers 部署实战:从零到生产

作者:君知博客团队
52 分钟阅读
#Cloudflare#Workers#边缘计算#部署#性能优化

Cloudflare Workers 部署实战:从零到生产

Cloudflare Workers 是一个强大的边缘计算平台,可以让你的应用在全球 200+ 个数据中心运行。本文将详细介绍如何部署和优化你的应用。

什么是 Cloudflare Workers?

Cloudflare Workers 是基于 V8 引擎的无服务器平台,运行在 Cloudflare 的边缘网络上。

主要优势

  1. 全球分布:在 200+ 个城市运行,用户访问最近的节点
  2. 极速响应:平均响应时间 < 50ms
  3. 无冷启动:不像传统 Serverless,Workers 没有冷启动问题
  4. 免费额度:每天 100,000 次请求免费
  5. 简单定价:超出免费额度后,$5/月 1000 万次请求

环境准备

1. 安装 Wrangler CLI

# 使用 npm 安装
npm install -g wrangler

# 或使用 pnpm
pnpm add -g wrangler

# 验证安装
wrangler --version

2. 登录 Cloudflare

# 登录你的 Cloudflare 账号
wrangler login

# 这会打开浏览器进行授权

3. 创建项目

# 创建新的 Workers 项目
wrangler init my-worker

# 选择项目类型
# - TypeScript (推荐)
# - JavaScript

部署 Next.js 到 Cloudflare Pages

1. 安装依赖

npm install --save-dev @cloudflare/next-on-pages

2. 配置 next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  // 静态导出模式
  output: 'export',

  // 图片优化配置
  images: {
    unoptimized: true, // Cloudflare Pages 不支持动态图片优化
  },

  // 尾部斜杠
  trailingSlash: true,
}

module.exports = nextConfig

3. 添加构建脚本

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "pages:build": "npx @cloudflare/next-on-pages",
    "pages:deploy": "npm run pages:build && wrangler pages deploy .vercel/output/static",
    "pages:dev": "npx wrangler pages dev .vercel/output/static --compatibility-flag=nodejs_compat"
  }
}

4. 构建和部署

# 构建项目
npm run pages:build

# 部署到 Cloudflare Pages
npm run pages:deploy

# 或者一步完成
npm run pages:deploy

Workers 基础开发

1. 简单的 Hello World

// src/index.ts
export default {
  async fetch(request: Request): Promise<Response> {
    return new Response('Hello from Cloudflare Workers!', {
      headers: {
        'content-type': 'text/plain',
      },
    })
  },
}

2. 处理不同的 HTTP 方法

export default {
  async fetch(request: Request): Promise<Response> {
    const { method, url } = request
    const { pathname } = new URL(url)

    // 路由处理
    if (pathname === '/api/users') {
      switch (method) {
        case 'GET':
          return handleGetUsers()
        case 'POST':
          return handleCreateUser(request)
        default:
          return new Response('Method not allowed', { status: 405 })
      }
    }

    return new Response('Not found', { status: 404 })
  },
}

async function handleGetUsers(): Promise<Response> {
  const users = [
    { id: 1, name: '张三' },
    { id: 2, name: '李四' },
  ]

  return new Response(JSON.stringify(users), {
    headers: {
      'content-type': 'application/json',
    },
  })
}

async function handleCreateUser(request: Request): Promise<Response> {
  const body = await request.json()

  // 验证数据
  if (!body.name) {
    return new Response('Name is required', { status: 400 })
  }

  // 创建用户(这里只是示例)
  const newUser = {
    id: Date.now(),
    name: body.name,
  }

  return new Response(JSON.stringify(newUser), {
    status: 201,
    headers: {
      'content-type': 'application/json',
    },
  })
}

3. 使用 KV 存储

// wrangler.toml
// [[kv_namespaces]]
// binding = "MY_KV"
// id = "your-kv-namespace-id"

interface Env {
  MY_KV: KVNamespace
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const { pathname } = new URL(request.url)

    if (pathname === '/api/cache') {
      // 读取缓存
      const cached = await env.MY_KV.get('my-key')
      if (cached) {
        return new Response(cached)
      }

      // 生成新数据
      const data = { timestamp: Date.now() }
      const value = JSON.stringify(data)

      // 写入缓存(TTL: 1小时)
      await env.MY_KV.put('my-key', value, {
        expirationTtl: 3600,
      })

      return new Response(value)
    }

    return new Response('Not found', { status: 404 })
  },
}

性能优化技巧

1. 使用缓存 API

export default {
  async fetch(request: Request): Promise<Response> {
    const cache = caches.default
    const cacheKey = new Request(request.url, request)

    // 尝试从缓存读取
    let response = await cache.match(cacheKey)

    if (!response) {
      // 缓存未命中,获取新数据
      response = await fetch('https://api.example.com/data')

      // 克隆响应并缓存
      response = new Response(response.body, response)
      response.headers.set('Cache-Control', 'max-age=3600')

      // 存入缓存
      await cache.put(cacheKey, response.clone())
    }

    return response
  },
}

2. 边缘 SSR

// 在边缘渲染 HTML
export default {
  async fetch(request: Request): Promise<Response> {
    const data = await fetchData()

    const html = `
      <!DOCTYPE html>
      <html>
        <head>
          <title>边缘 SSR</title>
        </head>
        <body>
          <h1>数据:${data.title}</h1>
          <p>${data.content}</p>
        </body>
      </html>
    `

    return new Response(html, {
      headers: {
        'content-type': 'text/html;charset=UTF-8',
      },
    })
  },
}

async function fetchData() {
  // 从数据库或 API 获取数据
  return {
    title: '示例标题',
    content: '示例内容',
  }
}

3. 请求合并

// 合并多个 API 请求
export default {
  async fetch(request: Request): Promise<Response> {
    // 并行请求多个 API
    const [users, posts, comments] = await Promise.all([
      fetch('https://api.example.com/users'),
      fetch('https://api.example.com/posts'),
      fetch('https://api.example.com/comments'),
    ])

    const data = {
      users: await users.json(),
      posts: await posts.json(),
      comments: await comments.json(),
    }

    return new Response(JSON.stringify(data), {
      headers: {
        'content-type': 'application/json',
      },
    })
  },
}

安全最佳实践

1. CORS 配置

function corsHeaders(origin: string) {
  return {
    'Access-Control-Allow-Origin': origin,
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Max-Age': '86400',
  }
}

export default {
  async fetch(request: Request): Promise<Response> {
    const origin = request.headers.get('Origin') || '*'

    // 处理 OPTIONS 预检请求
    if (request.method === 'OPTIONS') {
      return new Response(null, {
        headers: corsHeaders(origin),
      })
    }

    // 处理实际请求
    const response = await handleRequest(request)

    // 添加 CORS 头
    Object.entries(corsHeaders(origin)).forEach(([key, value]) => {
      response.headers.set(key, value)
    })

    return response
  },
}

2. 速率限制

interface Env {
  RATE_LIMITER: KVNamespace
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const ip = request.headers.get('CF-Connecting-IP') || 'unknown'
    const key = `rate-limit:${ip}`

    // 获取当前请求次数
    const count = await env.RATE_LIMITER.get(key)
    const currentCount = count ? parseInt(count) : 0

    // 检查是否超过限制(每分钟 60 次)
    if (currentCount >= 60) {
      return new Response('Too many requests', {
        status: 429,
        headers: {
          'Retry-After': '60',
        },
      })
    }

    // 增加计数
    await env.RATE_LIMITER.put(key, (currentCount + 1).toString(), {
      expirationTtl: 60, // 1 分钟后过期
    })

    // 处理请求
    return new Response('OK')
  },
}

3. 环境变量和密钥

# wrangler.toml
[vars]
ENVIRONMENT = "production"

# 敏感信息使用 secrets
# wrangler secret put API_KEY
interface Env {
  ENVIRONMENT: string
  API_KEY: string
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // 使用环境变量
    console.log(`Environment: ${env.ENVIRONMENT}`)

    // 使用密钥
    const response = await fetch('https://api.example.com/data', {
      headers: {
        'Authorization': `Bearer ${env.API_KEY}`,
      },
    })

    return response
  },
}

监控和调试

1. 日志记录

export default {
  async fetch(request: Request): Promise<Response> {
    const start = Date.now()

    try {
      const response = await handleRequest(request)

      // 记录成功请求
      console.log({
        method: request.method,
        url: request.url,
        status: response.status,
        duration: Date.now() - start,
      })

      return response
    } catch (error) {
      // 记录错误
      console.error({
        method: request.method,
        url: request.url,
        error: error.message,
        duration: Date.now() - start,
      })

      return new Response('Internal Server Error', { status: 500 })
    }
  },
}

2. 本地开发

# 启动本地开发服务器
wrangler dev

# 指定端口
wrangler dev --port 8787

# 启用远程模式(使用真实的 KV 等资源)
wrangler dev --remote

3. 查看日志

# 实时查看生产环境日志
wrangler tail

# 查看特定 Worker 的日志
wrangler tail my-worker

常见问题

1. 请求大小限制

Workers 有以下限制:

  • 请求体大小:最大 100 MB
  • 响应体大小:无限制
  • CPU 时间:最大 50ms(免费版)/ 30s(付费版)

2. 不支持的 Node.js API

Workers 运行在 V8 引擎上,不支持所有 Node.js API。使用兼容的替代方案:

// ❌ 不支持
import fs from 'fs'

// ✅ 使用 Web API
const response = await fetch('https://example.com/file.txt')
const text = await response.text()

3. 冷启动优化

虽然 Workers 没有传统意义的冷启动,但首次请求可能稍慢:

// 预加载数据
let cachedData: any = null

export default {
  async fetch(request: Request): Promise<Response> {
    if (!cachedData) {
      cachedData = await loadData()
    }

    return new Response(JSON.stringify(cachedData))
  },
}

总结

Cloudflare Workers 为我们提供了强大的边缘计算能力。关键要点:

  1. 充分利用边缘网络,减少延迟
  2. 合理使用缓存,提升性能
  3. 注意资源限制,优化代码
  4. 重视安全配置,保护应用
  5. 做好监控日志,快速定位问题

通过这些实践,你将能够构建出高性能、全球可用的应用。

相关资源


标签: #Cloudflare #Workers #边缘计算 #部署 #性能优化

发布日期: 2025-02-05

作者: 君知博客团队