
Cloudflare Workers — Photo by Carlos Muza on Unsplash
Cloudflare Workers: พลังแห่ง Serverless ที่ขอบของเครือข่าย
ปฏิวัติการพัฒนาเว็บด้วย JavaScript ที่ทำงานใกล้ผู้ใช้มากที่สุด
1. ทำความเข้าใจ Cloudflare Workers
Workers คืออะไร?
- นิยาม: Cloudflare Workers คือแพลตฟอร์ม serverless ที่ให้คุณรันโค้ด JavaScript/WebAssembly ที่ edge ของเครือข่าย Cloudflare
- ทำงานที่ไหน: ทำงานบนเซิร์ฟเวอร์กว่า 275 เมืองทั่วโลก ใกล้กับผู้ใช้มากที่สุด
- ความแตกต่าง: ไม่เหมือนกับ cloud functions ทั่วไปที่ทำงานในศูนย์ข้อมูลเพียงไม่กี่แห่ง
- ประสิทธิภาพ: เริ่มทำงานในเวลาน้อยกว่า 1 มิลลิวินาที (cold start เร็วมาก)
ทำไมต้องใช้ Workers?
- ความเร็ว: ลด latency เพราะโค้ดทำงานใกล้ผู้ใช้
- ความยืดหยุ่น: ปรับแต่งการทำงานของเว็บไซต์ได้โดยไม่ต้องแก้ไขแอปพลิเคชันหลัก
- ประหยัด: ฟรีสำหรับ 100,000 requests ต่อวัน
- ง่ายต่อการ scale: รองรับการขยายตัวโดยอัตโนมัติ ไม่ต้องจัดการเซิร์ฟเวอร์
2. เปรียบเทียบ Workers กับ Serverless Platforms อื่นๆ
Workers vs AWS Lambda
คุณสมบัติ | Cloudflare Workers | AWS Lambda |
---|---|---|
Cold Start | < 1 ms | 100-400 ms |
ภาษาที่รองรับ | JavaScript, WebAssembly | หลากหลายภาษา |
การกระจายตัว | 275+ เมืองทั่วโลก | 20+ regions |
Free Tier | 100,000 requests/วัน | 1,000,000 requests/เดือน |
ราคาเพิ่มเติม | $0.50/ล้าน requests | $0.20/ล้าน requests + ค่า compute time |
Workers vs Google Cloud Functions
คุณสมบัติ | Cloudflare Workers | Google Cloud Functions |
---|---|---|
Cold Start | < 1 ms | 100-500 ms |
ภาษาที่รองรับ | JavaScript, WebAssembly | Node.js, Python, Go, Java, .NET |
การกระจายตัว | 275+ เมืองทั่วโลก | 20+ regions |
Free Tier | 100,000 requests/วัน | 2,000,000 requests/เดือน |
ข้อจำกัด | 10ms CPU time/request (ฟรี) | 400,000 GB-seconds/เดือน |
3. การเริ่มต้นใช้งาน Workers
ขั้นตอนการติดตั้ง
-
ติดตั้ง Wrangler CLI
npm install -g @cloudflare/wrangler
-
ล็อกอินเข้าสู่ Cloudflare
wrangler login
-
สร้างโปรเจกต์ใหม่
wrangler init my-worker cd my-worker
-
แก้ไขไฟล์ src/index.js
export default { async fetch(request, env, ctx) { return new Response("Hello World!"); } };
-
ทดสอบโค้ดในเครื่อง
wrangler dev
-
เผยแพร่ Worker
wrangler publish
โครงสร้างโปรเจกต์พื้นฐาน
my-worker/
├── src/
│ └── index.js # โค้ดหลักของ Worker
├── wrangler.toml # ไฟล์การตั้งค่า
└── package.json # dependencies
การตั้งค่าใน wrangler.toml
name = "my-worker"
main = "src/index.js"
compatibility_date = "2023-05-18"
[triggers]
routes = [
{ pattern = "example.com/api/*", zone_name = "example.com" }
]
4. การเขียน Worker แบบพื้นฐาน
รูปแบบการเขียน Worker
export default {
// ฟังก์ชัน fetch จะทำงานเมื่อมี HTTP request เข้ามา
async fetch(request, env, ctx) {
// request: Request Object ของ fetch API
// env: environment variables
// ctx: context object สำหรับใช้งานฟีเจอร์เพิ่มเติม
// สร้าง Response กลับไป
return new Response("Hello World!", {
headers: { "Content-Type": "text/plain" }
});
}
};
การจัดการกับ Request
export default {
async fetch(request, env, ctx) {
// ดึงข้อมูลจาก URL
const url = new URL(request.url);
const path = url.pathname;
// ดึง HTTP method
const method = request.method;
// ดึง headers
const userAgent = request.headers.get("User-Agent");
// ดึง query parameters
const name = url.searchParams.get("name") || "Guest";
// สร้าง response ตามเงื่อนไข
if (path === "/api/hello") {
return new Response(`Hello, ${name}!`, {
headers: { "Content-Type": "text/plain" }
});
}
// ถ้าไม่ตรงกับเงื่อนไขใดๆ
return new Response("Not Found", { status: 404 });
}
};
การจัดการกับ JSON
export default {
async fetch(request, env, ctx) {
// ตรวจสอบว่าเป็น POST request หรือไม่
if (request.method === "POST") {
// แปลง request body เป็น JSON
const data = await request.json();
// ประมวลผลข้อมูล
const result = {
message: `Hello, ${data.name}!`,
timestamp: new Date().toISOString()
};
// ส่ง JSON response กลับไป
return new Response(JSON.stringify(result), {
headers: {
"Content-Type": "application/json"
}
});
}
return new Response("Method not allowed", { status: 405 });
}
};
5. ตัวอย่างการใช้งานจริง
1. API Proxy และ Transformation
export default {
async fetch(request, env, ctx) {
// สร้าง URL ของ API ที่ต้องการเรียก
const apiUrl = "https://jsonplaceholder.typicode.com/posts";
// เรียก API ภายนอก
const response = await fetch(apiUrl);
const posts = await response.json();
// แปลงข้อมูลก่อนส่งกลับ
const transformedPosts = posts.slice(0, 5).map(post => ({
title: post.title.toUpperCase(),
snippet: post.body.slice(0, 50) + "..."
}));
// ส่งข้อมูลที่แปลงแล้วกลับไป
return new Response(JSON.stringify(transformedPosts), {
headers: {
"Content-Type": "application/json",
"Cache-Control": "s-maxage=60"
}
});
}
};
2. A/B Testing
export default {
async fetch(request, env, ctx) {
// สร้าง URL object
const url = new URL(request.url);
// สุ่มเลือกเวอร์ชัน A หรือ B
const version = Math.random() < 0.5 ? "A" : "B";
// สร้าง response ตามเวอร์ชัน
let response;
if (version === "A") {
response = new Response(`
<html>
<body style="background-color: #f0f0f0;">
<h1>Welcome to Version A</h1>
<p>This is the control version of our page.</p>
</body>
</html>
`, {
headers: { "Content-Type": "text/html" }
});
} else {
response = new Response(`
<html>
<body style="background-color: #e0f7fa;">
<h1>Welcome to Version B</h1>
<p>This is the experimental version with a new design.</p>
</body>
</html>
`, {
headers: { "Content-Type": "text/html" }
});
}
// เพิ่ม header เพื่อติดตามว่าผู้ใช้เห็นเวอร์ชันไหน
response.headers.set("X-Version", version);
return response;
}
};
3. Image Optimization
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const imageUrl = url.searchParams.get("url");
const width = url.searchParams.get("width") || "800";
const format = url.searchParams.get("format") || "webp";
if (!imageUrl) {
return new Response("Missing 'url' parameter", { status: 400 });
}
// สร้าง URL สำหรับ Cloudflare Image Resizing
const resizeUrl = new URL(imageUrl);
resizeUrl.searchParams.set("width", width);
resizeUrl.searchParams.set("format", format);
// เรียกใช้ Cloudflare Image Resizing API
const imageResponse = await fetch(resizeUrl.toString(), {
cf: {
image: {
width: parseInt(width),
format: format
}
}
});
// ส่งรูปภาพที่ปรับขนาดแล้วกลับไป
return new Response(imageResponse.body, {
headers: {
"Content-Type": `image/${format}`,
"Cache-Control": "public, max-age=31536000"
}
});
}
};
6. การใช้งาน Workers KV
Workers KV คืออะไร?
- นิยาม: Key-Value storage ที่ทำงานร่วมกับ Workers
- ความเร็ว: อ่านข้อมูลได้เร็วมาก (เฉลี่ย < 10ms ทั่วโลก)
- ขนาด: เก็บข้อมูลได้สูงสุด 25MB ต่อ key
- Free Tier: 1GB storage, 100,000 read operations/วัน, 1,000 write operations/วัน
การตั้งค่า KV Namespace
-
สร้าง KV Namespace
wrangler kv:namespace create "MY_KV"
-
เพิ่มใน wrangler.toml
[[kv_namespaces]] binding = "MY_KV" id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
การใช้งาน KV ใน Worker
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const path = url.pathname;
// อ่านข้อมูลจาก KV
if (path === "/api/get") {
const key = url.searchParams.get("key");
if (!key) {
return new Response("Missing 'key' parameter", { status: 400 });
}
const value = await env.MY_KV.get(key);
if (value === null) {
return new Response("Key not found", { status: 404 });
}
return new Response(value);
}
// เขียนข้อมูลลง KV
if (path === "/api/set" && request.method === "POST") {
const { key, value } = await request.json();
if (!key || !value) {
return new Response("Missing 'key' or 'value'", { status: 400 });
}
await env.MY_KV.put(key, value);
return new Response("Value stored successfully");
}
return new Response("Not Found", { status: 404 });
}
};
ตัวอย่างการใช้ KV เป็น Cache
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const apiPath = url.pathname.replace("/api/", "");
// สร้าง cache key จาก URL
const cacheKey = `data-${apiPath}`;
// พยายามดึงข้อมูลจาก cache ก่อน
const cachedData = await env.MY_KV.get(cacheKey, { type: "json" });
if (cachedData) {
return new Response(JSON.stringify(cachedData), {
headers: {
"Content-Type": "application/json",
"X-Cache": "HIT"
}
});
}
// ถ้าไม่มีใน cache ให้เรียก API จริง
const apiUrl = `https://api.example.com/${apiPath}`;
const response = await fetch(apiUrl);
const data = await response.json();
// เก็บข้อมูลลง cache (หมดอายุใน 1 ชั่วโมง)
await env.MY_KV.put(cacheKey, JSON.stringify(data), { expirationTtl: 3600 });
// ส่งข้อมูลกลับไป
return new Response(JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
"X-Cache": "MISS"
}
});
}
};
7. การใช้งาน Durable Objects
Durable Objects คืออะไร?
- นิยาม: Objects ที่เก็บสถานะและทำงานใน single-region
- ความสามารถ: รองรับการทำงานที่ต้องการความสอดคล้องของข้อมูล (consistency)
- Use Cases: เกม realtime, chat applications, counters, locks
- ข้อจำกัด: ไม่มีใน Free Tier (ต้องใช้แพ็กเกจ Paid)
การตั้งค่า Durable Objects
-
เพิ่มใน wrangler.toml
[durable_objects] bindings = [ { name = "COUNTER", class_name = "Counter" } ] [[migrations]] tag = "v1" new_classes = ["Counter"]
-
สร้าง Migration
wrangler publish --new-class Counter
ตัวอย่าง Counter ด้วย Durable Objects
// ประกาศ Durable Object class
export class Counter {
constructor(state, env) {
this.state = state;
this.storage = state.storage;
}
// จัดการกับ HTTP requests
async fetch(request) {
const url = new URL(request.url);
let value = await this.storage.get("counter") || 0;
// เพิ่มค่า counter
if (url.pathname === "/increment") {
value++;
await this.storage.put("counter", value);
}
// ลดค่า counter
if (url.pathname === "/decrement") {
value--;
await this.storage.put("counter", value);
}
// ส่งค่าปัจจุบันกลับไป
return new Response(value.toString());
}
}
// Worker ที่เรียกใช้ Durable Object
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
const counterId = env.COUNTER.idFromName("global_counter");
const counterObj = env.COUNTER.get(counterId);
// ส่งต่อ request ไปยัง Durable Object
return counterObj.fetch(request);
}
};
8. การ Debug และ Testing
การ Debug ใน Local Environment
-
ใช้ wrangler dev
wrangler dev
- เปิด local server ที่ port 8787
- Hot reloading เมื่อแก้ไขโค้ด
- แสดง console.log() ใน terminal
-
การใช้ console.log()
export default { async fetch(request, env, ctx) { console.log("Request received:", request.url); console.log("Method:", request.method); // ทดลองดู headers const headers = {}; for (const [key, value] of request.headers.entries()) { headers[key] = value; console.log(`Header: ${key} = ${value}`); } return new Response("Check your console for logs"); } };
การทดสอบ Workers
-
Unit Testing ด้วย Jest
ติดตั้ง dependencies:
npm install --save-dev jest @cloudflare/workers-types
สร้างไฟล์ test:
// worker.test.js import { unstable_dev } from 'wrangler'; describe('Worker', () => { let worker; beforeAll(async () => { worker = await unstable_dev('src/index.js'); }); afterAll(async () => { await worker.stop(); }); it('should return Hello World', async () => { const resp = await worker.fetch(); const text = await resp.text(); expect(text).toContain('Hello World'); }); it('should return JSON for /api endpoint', async () => { const resp = await worker.fetch('/api'); const data = await resp.json(); expect(resp.headers.get('Content-Type')).toContain('application/json'); expect(data).toHaveProperty('message'); }); });
-
การทดสอบด้วย Postman หรือ cURL
ทดสอบด้วย cURL:
# GET request curl http://localhost:8787/api/hello?name=John # POST request curl -X POST http://localhost:8787/api/data \ -H "Content-Type: application/json" \ -d '{"name":"John","age":30}'
9. การ Deploy และ Monitoring
การ Deploy
-
Deploy ด้วย Wrangler
wrangler publish
-
การตั้งค่า Custom Domain
- ไปที่ Cloudflare Dashboard > Workers & Pages
- เลือก Worker ที่ต้องการ
- คลิก “Triggers” > “Add Custom Domain”
- ใส่โดเมนที่ต้องการ (ต้องอยู่ใน Cloudflare แล้ว)
-
การตั้งค่า Routes
# ใน wrangler.toml [triggers] routes = [ { pattern = "api.example.com/*", zone_name = "example.com" }, { pattern = "example.com/api/*", zone_name = "example.com" } ]
การ Monitoring
-
Cloudflare Analytics
- ไปที่ Cloudflare Dashboard > Workers & Pages > Analytics
- ดูข้อมูล:
- จำนวน Requests
- CPU Time
- ข้อผิดพลาด
- การกระจายตัวทางภูมิศาสตร์
-
การใช้ Logs
- เปิดใช้งาน Logs ใน Dashboard
- ดู Logs แบบ Real-time ด้วย:
wrangler tail
-
การตั้งค่า Alerts
- ตั้งค่าการแจ้งเตือนเมื่อ:
- Error rate สูงเกินกำหนด
- CPU time สูงเกินไป
- จำนวน requests เกินโควต้า
- ตั้งค่าการแจ้งเตือนเมื่อ:
10. ข้อจำกัดและการอัพเกรด
ข้อจำกัดของ Free Tier
- Requests: 100,000 requests/วัน
- CPU Time: 10ms ต่อ request
- Memory: 128MB ต่อ request
- Environment Variables: จำกัด 32 ตัว
- Script Size: สูงสุด 1MB
- KV Storage: 1GB
- Durable Objects: ไม่มีในแพ็กเกจฟรี
เมื่อไรควรอัพเกรด
-
ปริมาณการใช้งาน:
- มี requests เกิน 100,000 ต่อวัน
- ต้องการ CPU time มากกว่า 10ms ต่อ request
-
ฟีเจอร์เพิ่มเติม:
- ต้องการใช้ Durable Objects
- ต้องการ KV storage มากกว่า 1GB
- ต้องการ Cron Triggers (ทำงานตามเวลาที่กำหนด)
-
การสนับสนุน:
- ต้องการ Support แบบ Priority
- ต้องการ SLA (Service Level Agreement)
แพ็กเกจที่แนะนำ
-
Workers Paid: $5/เดือน + $0.50/ล้าน requests
- เหมาะสำหรับโปรเจกต์ที่มีทราฟฟิกปานกลาง
- ได้ 10 ล้าน requests/เดือน
- CPU time 50ms ต่อ request
-
Workers Unbound: จ่ายตามการใช้งานจริง
- เหมาะสำหรับโปรเจกต์ขนาดใหญ่
- ไม่มีข้อจำกัดด้าน requests
- CPU time สูงสุด 30 วินาทีต่อ request
11. กรณีศึกษา: การใช้งานจริงของ Startup
กรณีศึกษา 1: E-commerce API Gateway
- ความท้าทาย: Startup ด้าน e-commerce ต้องการลด latency ของ API และเพิ่มความปลอดภัย
- การใช้ Workers:
- สร้าง API Gateway ที่ทำหน้าที่ตรวจสอบ authentication
- แคชข้อมูลสินค้าด้วย KV
- ปรับแต่งข้อมูลก่อนส่งไปยังเบราว์เซอร์
- ผลลัพธ์:
- ลด latency ลง 60%
- ลดภาระของ backend servers
- เพิ่มความปลอดภัยด้วยการกรอง requests ที่ไม่ถูกต้อง
กรณีศึกษา 2: Content Personalization
- ความท้าทาย: เว็บไซต์ข่าวต้องการแสดงเนื้อหาที่แตกต่างกันตามภูมิภาคของผู้ใช้
- การใช้ Workers:
- ตรวจสอบตำแหน่งของผู้ใช้จาก Cloudflare’s CF-IPCountry header
- ปรับเปลี่ยนเนื้อหาตามภูมิภาค
- แคชข้อมูลแยกตามภูมิภาคด้วย KV
- ผลลัพธ์:
- เพิ่ม engagement ของผู้ใช้ 25%
- ลดเวลาในการโหลดเว็บไซต์
- ไม่ต้องแก้ไขระบบหลัก
กรณีศึกษา 3: Authentication Middleware
- ความท้าทาย: SaaS platform ต้องการระบบ authentication ที่เร็วและปลอดภัย
- การใช้ Workers:
- ตรวจสอบ JWT tokens ที่ edge
- จัดการ rate limiting เพื่อป้องกัน brute force attacks
- เก็บข้อมูล session ใน KV
- ผลลัพธ์:
- ลดภาระของ authentication servers
- เพิ่มความปลอดภัยด้วยการตรวจสอบที่ edge
- ลด latency ของการตรวจสอบ token
12. สรุป: ทำไม Cloudflare Workers ถึงเหมาะกับ Startup
-
ประหยัดต้นทุน
เริ่มต้นฟรี และขยายตามการเติบโตของธุรกิจ -
ประสิทธิภาพสูง
ลด latency ด้วยการทำงานที่ edge ใกล้ผู้ใช้ -
ลดความซับซ้อน
ไม่ต้องจัดการเซิร์ฟเวอร์ ทำให้โฟกัสกับการพัฒนาธุรกิจ -
ความยืดหยุ่น
ปรับแต่งการทำงานของเว็บไซต์ได้โดยไม่ต้องแก้ไขระบบหลัก -
ความปลอดภัย
เพิ่มชั้นความปลอดภัยที่ edge ก่อนถึงระบบหลัก
“Cloudflare Workers เป็นเครื่องมือที่ทรงพลังสำหรับ Startup ที่ต้องการสร้างแอปพลิเคชันที่เร็ว ปลอดภัย และประหยัดต้นทุน โดยไม่ต้องกังวลเรื่องการจัดการ infrastructure”
13. แหล่งเรียนรู้เพิ่มเติม
เอกสารและบทความ:
คอมมูนิตี้:
คอร์สและวิดีโอ:
เคล็ดลับ: Cloudflare มีการอัพเดทฟีเจอร์ใหม่ๆ สำหรับ Workers อยู่เสมอ ติดตาม Cloudflare Blog และ Twitter เพื่อไม่พลาดฟีเจอร์ล่าสุดที่อาจช่วยให้แอปพลิเคชันของคุณดียิ่งขึ้น