cloudflare-expert

安装量: 37
排名: #18954

安装

npx skills add https://github.com/personamanagmentlayer/pcl --skill cloudflare-expert

Expert guidance for Cloudflare Workers, edge computing, CDN optimization, and Cloudflare security services.

Core Concepts

Cloudflare Services

  • Cloudflare Workers (serverless edge computing)

  • CDN and caching

  • DDoS protection

  • Web Application Firewall (WAF)

  • DNS management

  • Load balancing

  • Workers KV (key-value storage)

  • Durable Objects

Edge Computing

  • Deploy code globally

  • Reduce latency

  • Process at the edge

  • Distributed state

  • Real-time applications

Developer Tools

  • Wrangler CLI

  • Workers Playground

  • Edge APIs

  • Analytics and logs

Cloudflare Workers

// Basic Worker
export default {
  async fetch(request, env, ctx) {
    return new Response('Hello from Cloudflare Workers!', {
      headers: { 'Content-Type': 'text/plain' }
    });
  }
};

// Advanced routing
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    // Route based on path
    switch (url.pathname) {
      case '/api/users':
        return handleUsers(request, env);
      case '/api/posts':
        return handlePosts(request, env);
      default:
        return new Response('Not Found', { status: 404 });
    }
  }
};

// API endpoint with JSON
async function handleUsers(request, env) {
  if (request.method === 'GET') {
    const users = await env.USERS_KV.get('users', { type: 'json' });
    return new Response(JSON.stringify(users), {
      headers: { 'Content-Type': 'application/json' }
    });
  }

  if (request.method === 'POST') {
    const body = await request.json();
    await env.USERS_KV.put('users', JSON.stringify(body));
    return new Response('Created', { status: 201 });
  }

  return new Response('Method Not Allowed', { status: 405 });
}

Workers KV Storage

// Workers KV operations
export default {
  async fetch(request, env, ctx) {
    // Write
    await env.MY_KV.put('key', 'value');

    // Write with metadata and expiration
    await env.MY_KV.put('key', 'value', {
      metadata: { userId: '123' },
      expirationTtl: 3600 // 1 hour
    });

    // Read
    const value = await env.MY_KV.get('key');

    // Read as JSON
    const jsonValue = await env.MY_KV.get('key', { type: 'json' });

    // Read with metadata
    const { value, metadata } = await env.MY_KV.getWithMetadata('key');

    // Delete
    await env.MY_KV.delete('key');

    // List keys
    const keys = await env.MY_KV.list({ prefix: 'user:' });

    return new Response(JSON.stringify({ value, keys }));
  }
};

// Caching pattern
class CachedAPI {
  constructor(kv) {
    this.kv = kv;
  }

  async get(key, fetcher, ttl = 3600) {
    // Try cache first
    const cached = await this.kv.get(key, { type: 'json' });
    if (cached) return cached;

    // Fetch and cache
    const data = await fetcher();
    await this.kv.put(key, JSON.stringify(data), {
      expirationTtl: ttl
    });

    return data;
  }
}

export default {
  async fetch(request, env, ctx) {
    const cache = new CachedAPI(env.MY_KV);

    const data = await cache.get('api:users', async () => {
      const response = await fetch('https://api.example.com/users');
      return response.json();
    }, 3600);

    return new Response(JSON.stringify(data));
  }
};

Durable Objects

// Durable Object for stateful logic
export class Counter {
  constructor(state, env) {
    this.state = state;
    this.value = 0;
  }

  async initialize() {
    this.value = await this.state.storage.get('value') || 0;
  }

  async fetch(request) {
    await this.initialize();

    const url = new URL(request.url);

    if (url.pathname === '/increment') {
      this.value++;
      await this.state.storage.put('value', this.value);
      return new Response(String(this.value));
    }

    if (url.pathname === '/decrement') {
      this.value--;
      await this.state.storage.put('value', this.value);
      return new Response(String(this.value));
    }

    return new Response(String(this.value));
  }
}

// WebSocket chat room with Durable Objects
export class ChatRoom {
  constructor(state, env) {
    this.state = state;
    this.sessions = [];
  }

  async fetch(request) {
    if (request.headers.get('Upgrade') !== 'websocket') {
      return new Response('Expected WebSocket', { status: 426 });
    }

    const pair = new WebSocketPair();
    const [client, server] = Object.values(pair);

    await this.handleSession(server);

    return new Response(null, {
      status: 101,
      webSocket: client
    });
  }

  async handleSession(websocket) {
    websocket.accept();
    this.sessions.push(websocket);

    websocket.addEventListener('message', async (msg) => {
      // Broadcast to all sessions
      for (const session of this.sessions) {
        try {
          session.send(msg.data);
        } catch (err) {
          // Remove closed sessions
          this.sessions = this.sessions.filter(s => s !== session);
        }
      }
    });
  }
}

// Worker that uses Durable Object
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const roomId = url.pathname.slice(1);

    // Get or create Durable Object
    const id = env.CHAT_ROOM.idFromName(roomId);
    const stub = env.CHAT_ROOM.get(id);

    return stub.fetch(request);
  }
};

Request/Response Handling

// CORS handling
function handleCORS(request) {
  const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization'
  };

  // Handle preflight
  if (request.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders });
  }

  return corsHeaders;
}

// Authentication middleware
async function authenticate(request, env) {
  const token = request.headers.get('Authorization')?.replace('Bearer ', '');

  if (!token) {
    return new Response('Unauthorized', { status: 401 });
  }

  // Verify token (example using JWT)
  try {
    const payload = await verifyJWT(token, env.JWT_SECRET);
    return payload;
  } catch (err) {
    return new Response('Invalid token', { status: 401 });
  }
}

// Rate limiting
class RateLimiter {
  constructor(kv) {
    this.kv = kv;
  }

  async checkLimit(identifier, maxRequests, windowSeconds) {
    const key = `rate_limit:${identifier}`;
    const now = Date.now();
    const windowMs = windowSeconds * 1000;

    // Get current count
    const data = await this.kv.get(key, { type: 'json' });

    if (!data || now - data.timestamp > windowMs) {
      // New window
      await this.kv.put(key, JSON.stringify({
        count: 1,
        timestamp: now
      }), { expirationTtl: windowSeconds });
      return true;
    }

    if (data.count >= maxRequests) {
      return false; // Rate limit exceeded
    }

    // Increment count
    data.count++;
    await this.kv.put(key, JSON.stringify(data), {
      expirationTtl: windowSeconds
    });

    return true;
  }
}

export default {
  async fetch(request, env, ctx) {
    const corsHeaders = handleCORS(request);
    if (request.method === 'OPTIONS') return corsHeaders;

    // Rate limiting
    const rateLimiter = new RateLimiter(env.RATE_LIMIT_KV);
    const clientIP = request.headers.get('CF-Connecting-IP');
    const allowed = await rateLimiter.checkLimit(clientIP, 100, 60);

    if (!allowed) {
      return new Response('Rate limit exceeded', {
        status: 429,
        headers: corsHeaders
      });
    }

    // Authentication
    const user = await authenticate(request, env);
    if (user instanceof Response) {
      return user; // Error response
    }

    // Process request
    const response = await handleRequest(request, env, user);

    // Add CORS headers to response
    Object.entries(corsHeaders).forEach(([key, value]) => {
      response.headers.set(key, value);
    });

    return response;
  }
};

Caching Strategies

// Cache API
async function cacheFirst(request) {
  const cache = caches.default;
  let response = await cache.match(request);

  if (!response) {
    response = await fetch(request);
    // Cache for 1 hour
    response = new Response(response.body, response);
    response.headers.set('Cache-Control', 'max-age=3600');
    await cache.put(request, response.clone());
  }

  return response;
}

// Stale-while-revalidate
async function staleWhileRevalidate(request, ctx) {
  const cache = caches.default;
  let response = await cache.match(request);

  // Background refresh
  ctx.waitUntil(
    fetch(request).then(freshResponse => {
      const clonedResponse = freshResponse.clone();
      cache.put(request, clonedResponse);
    })
  );

  if (response) {
    return response;
  }

  return fetch(request);
}

// Custom cache keys
function customCacheKey(request) {
  const url = new URL(request.url);

  // Ignore query parameters for caching
  url.search = '';

  // Add custom cache key based on headers
  const userAgent = request.headers.get('User-Agent');
  const isMobile = /mobile/i.test(userAgent);
  url.searchParams.set('device', isMobile ? 'mobile' : 'desktop');

  return new Request(url.toString(), request);
}

export default {
  async fetch(request, env, ctx) {
    const cacheKey = customCacheKey(request);

    if (request.url.includes('/api/')) {
      // API routes: stale-while-revalidate
      return staleWhileRevalidate(cacheKey, ctx);
    }

    // Static assets: cache first
    return cacheFirst(cacheKey);
  }
};

Edge Functions

// HTML rewriting
export default {
  async fetch(request, env, ctx) {
    const response = await fetch(request);

    // Inject analytics script
    return new HTMLRewriter()
      .on('head', new HeadInjector())
      .transform(response);
  }
};

class HeadInjector {
  element(element) {
    element.append(
      '<script>console.log("Injected at edge!");</script>',
      { html: true }
    );
  }
}

// Geolocation-based routing
export default {
  async fetch(request, env, ctx) {
    const country = request.cf.country;

    // Route based on country
    const apiEndpoint = {
      'US': 'https://us-api.example.com',
      'EU': 'https://eu-api.example.com',
      'default': 'https://global-api.example.com'
    }[country] || 'https://global-api.example.com';

    const url = new URL(request.url);
    const apiUrl = new URL(url.pathname, apiEndpoint);

    return fetch(apiUrl, request);
  }
};

// A/B testing
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    // Determine variant
    let variant = request.headers.get('Cookie')?.match(/variant=(\w+)/)?.[1];

    if (!variant) {
      variant = Math.random() < 0.5 ? 'A' : 'B';
    }

    // Fetch appropriate version
    const response = await fetch(`${url.origin}/variant-${variant}${url.pathname}`);

    // Set cookie
    const newResponse = new Response(response.body, response);
    newResponse.headers.set('Set-Cookie', `variant=${variant}; Path=/; Max-Age=86400`);

    return newResponse;
  }
};

Wrangler CLI

# Initialize project
wrangler init my-worker

# Development server
wrangler dev

# Deploy to production
wrangler publish

# Deploy to specific environment
wrangler publish --env production

# Tail logs
wrangler tail

# KV operations
wrangler kv:namespace create "MY_KV"
wrangler kv:key put --namespace-id=<id> "key" "value"
wrangler kv:key get --namespace-id=<id> "key"

# Durable Objects
wrangler publish --new-class Counter

# Secrets
wrangler secret put SECRET_NAME

wrangler.toml Configuration

name =

返回排行榜