AI Web Studio977-121 · PSU PHUKET
รายงานวิจัย
ดาวน์โหลด Markdown

AI Web Studio · 977-121 · PSU Phuket

Cloudflare สำหรับเว็บไซต์ที่สร้างด้วย Vibe Coding

สถานะการวิจัย: 9 กันยายน 2026 · ข้อเท็จจริงทางเทคนิคในเอกสารนี้มาจากเอกสารทางการ Cloudflare ที่เปิดอ่านในวันนี้ ส่วนคำว่า ข้อเสนอแนะในการสอน คือการเลือกเนื้อหาสำหรับหน่วยเรียน 2 วัน / 8 ชั่วโมงและคลังศึกษาต่อ ไม่ใช่ข้อกำหนดของ Cloudflare

คำตอบสั้นสำหรับหลักสูตรนี้

สำหรับเว็บไซต์บริษัท หน้ารวมสินค้า และตัวอย่างแอนิเมชัน GSAP ให้เริ่มด้วย Cloudflare Worker + Workers Static Assets เป็นจุด deploy เดียว: build frontend ไปที่ dist/, ให้ Worker เสิร์ฟไฟล์เหล่านั้น และให้ route /api/* เรียก API เดียวกันได้ เมื่อมีข้อมูลเชิงสัมพันธ์จึง bind D1; เมื่อมีรูปสินค้า เอกสาร หรือไฟล์ผู้ใช้จึง bind R2; และก่อนรับฟอร์ม/การจองให้ใช้ Turnstile แล้วตรวจ token ใน Worker ฝั่ง server เสมอ. นี่ลดจำนวน deployment, domain, CORS และจุดที่ผู้เรียนต้อง debug ในโปรเจกต์แรก

Cloudflare ระบุว่า Workers Static Assets เป็นวิธีที่แนะนำสำหรับ static site, SPA และ full-stack app ใหม่; Pages ยังใช้งานได้ แต่ฟีเจอร์และการปรับปรุงใหม่มุ่งไปที่ Workers มากกว่า. ดังนั้นบทเรียนให้รู้จัก Pages เพื่ออ่านโปรเจกต์เก่าและการ deploy ที่มีอยู่ แต่ไม่ใช้ Pages เป็นค่าเริ่มต้นของงานใหม่ (Workers best practices).

ขอบเขตของ starter repository นี้

ข้อเสนอข้างต้นเป็นสถาปัตยกรรมเป้าหมายของหลักสูตร; starter ที่ใช้สอนตอนนี้มี Worker Static Assets + ASSETS binding + D1 binding เท่านั้น และ DEMO_MODE: "true". Repository ของผู้สอนอาจมี D1 resource ID ของ demo ที่ deploy แล้ว แต่ source package ที่แจกผู้เรียนแทนค่านั้นด้วย placeholder; ผู้เรียนต้องสร้าง D1 ของตนเองและใส่ ID ของตนตาม บทเรียน 08. ไม่มี R2 binding, named staging environment หรือ frontend Turnstile widget ที่ production-ready ใน starter. เส้นทางที่รันได้จริงคือ npm run db:localnpm run dev → smoke /api/health และ /api/catalognpm run deploy:check; อย่าอ้างว่า R2/staging/production deploy สำเร็จจนกว่าจะเพิ่ม resource, config, secret และ evidence ตามบทเรียนนั้น.

ขอบเขตและรูปแบบเว็บไซต์ตัวอย่าง

ตัวอย่าง ของที่ deploy ข้อมูล ความปลอดภัยขั้นต่ำ สิ่งที่พิสูจน์ได้
เว็บไซต์บริษัท Static Assets + /api/contact D1 สำหรับข้อความติดต่อ (ถ้าต้องเก็บ) Turnstile + validation ฝั่ง Worker ฟอร์มส่งสำเร็จและไม่มี secret ใน browser
แค็ตตาล็อก/โชว์สินค้า GSAP Static Assets + /api/catalog starter ส่ง catalogue demo; production อาจใช้ D1 และ R2 สำหรับภาพ validate input; cache read-only อย่างระวัง ภาพและ animation โหลดได้ พร้อมเคารพ prefers-reduced-motion
เว็บไซต์เช่าอุปกรณ์ Static Assets + API D1: อุปกรณ์, ลูกค้า, ช่วงเวลา, คำขอจอง; R2: รูป/เอกสาร Turnstile, prepared SQL, validation, rate limit ตามความเสี่ยง ไม่เกิดการจองซ้ำในกรณีแข่งกัน และมี audit log ที่ปลอดภัย
back office ของทีม Worker ที่ป้องกันด้วย Access D1/R2 ตามงาน Cloudflare Access/IdP และ policy แบบ deny-by-default คนที่ไม่ตรง policy เข้าไม่ได้

ข้อเสนอแนะในการสอน: อย่าเริ่มด้วย e-commerce ที่รับชำระเงินจริง หรือระบบบัญชีผู้ใช้เต็มรูปแบบ. ให้เริ่ม “catalogue + enquiry/reservation request” ก่อน แล้วอธิบายว่าการเก็บเงิน, อีเมล, ภาษี, สต็อก และการยืนยันตัวตนเป็น integration แยกที่ต้องออกแบบและทดสอบเพิ่ม.

แผนภาพสถาปัตยกรรมเริ่มต้น

แผนภาพสถาปัตยกรรม Cloudflare แสดง browser ผ่าน HTTPS เข้าสู่ Worker ที่ Cloudflare edge แล้วแยกไป static assets และ D1 managed dataแผนภาพสถาปัตยกรรม Cloudflare แสดง browser ผ่าน HTTPS เข้าสู่ Worker ที่ Cloudflare edge แล้วแยกไป static assets และ D1 managed data
บนจอเล็ก เลื่อนแนวนอนเพื่ออ่านแผนภาพ หรือเปิดไฟล์ HTML จากลิงก์ใต้ภาพ

เปิดแผนภาพ Cloudflare deployment แบบเต็มหน้า เพื่อดู topology ที่ starter มีจริง ส่วน R2, Access และ Turnstile เป็น production extensions ที่ตั้งใจตัดออกจากภาพเพื่อลดความหนาแน่นและอธิบายในตารางขอบเขตด้านบน

Static Assets อยู่ในไฟล์ config ผ่าน assets.directory. เว็บไซต์ล้วน ๆ ไม่ต้องมี Worker script; full-stack เพิ่ม main และใช้ ASSETS binding เพื่อให้ handler ส่ง static asset ที่ไม่ใช่ /api/* (แนวทางทางการ). ยึด wrangler.jsonc เป็น config ที่อยู่ใน Git, ใช้ compatibility_date ล่าสุดที่ทีมทดสอบแล้ว, และสร้าง type ของ binding หลังปรับ config. อย่า copy วันที่ในตัวอย่างโดยไม่ตรวจสอบวันที่ release/deploy จริง.

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "name": "course-catalogue",
  "main": "src/worker.ts",
  "compatibility_date": "YYYY-MM-DD",
  "assets": {
    "directory": "./dist", "binding": "ASSETS",
    "run_worker_first": ["/api/*"]
  },
  "d1_databases": [{
    "binding": "DB", "database_name": "course-catalogue",
    "database_id": "<created-by-cloudflare>", "migrations_dir": "migrations"
  }],
  "observability": { "enabled": true, "head_sampling_rate": 0.1 }
}

ตัวอย่างนี้เป็นโครง ไม่ใช่ค่าพร้อม deploy: database_id, route และ secret ต้องมาจากบัญชีของผู้เรียน. R2 เพิ่มได้เฉพาะเมื่อมี media route/authorization/test ที่ใช้จริง. หากเพิ่ม named environment, bindings และ vars ไม่ inherit; ต้องประกาศค่าของ staging/production ให้ครบ (Wrangler environments). ตรวจ schema/คำสั่งของ Wrangler เวอร์ชันที่ติดตั้งก่อน execute (Wrangler).

D1: SQL ที่ปลอดภัย, migration และการแข่งกัน

D1 เหมาะกับข้อมูลสัมพันธ์ขนาดของตัวอย่างนี้: catalogue, availability, booking request และ contact message. ห้ามต่อค่าจาก input เข้า SQL string. ใช้ prepare(...).bind(...): Cloudflare แนะนำ prepared statement เพราะการ bind ช่วย reuse และป้องกัน SQL injection (Prepared statements). ตรวจชนิด/ขอบเขต input ก่อน query และคืน error message ที่ไม่เผย SQL หรือ secret.

const row = await env.DB.prepare(
  "SELECT id, name, daily_rate FROM equipment WHERE id = ?"
).bind(equipmentId).first();

ไฟล์ migration คือส่วนหนึ่งของ source code: สร้างไฟล์ลำดับ migrations/0001_initial.sql, commit พร้อม code และใช้ wrangler d1 migrations apply <database> --local ก่อน จากนั้นตรวจ staging แล้วจึง --remote. D1 บันทึก migration ที่ apply แล้วในตาราง d1_migrations; ใช้ database name ในคำสั่ง migration เมื่อเป็นไปได้ เพราะ binding name เปลี่ยนได้ (D1 migrations). คำสั่ง DDL ที่เสี่ยงลบ/แก้ข้อมูลต้องมี backup/restore plan และต้อง rehearsal บน staging ก่อน production.

ใช้ DB.batch([...]) เมื่อต้องการหลาย prepared statements เป็นชุดเดียว: Cloudflare ระบุว่า batch ทำงานตามลำดับ, ไม่พร้อมกัน, และเป็น SQL transaction; หาก statement ใด fail จะ rollback ทั้งชุด (D1Database batch). สำหรับการจอง ให้ schema มี constraint ที่สะท้อนกติกาธุรกิจ และให้การตรวจ availability กับ insert/update อยู่ใน transaction เดียว—อย่าคิดว่า “SELECT ก่อนแล้วค่อย INSERT” สอง request จะแข่งกันไม่ได้.

D1 database หนึ่งตัว single-threaded และ query เข้าเป็นลำดับ; เมื่อ queue เต็มอาจเกิด overloaded. ลด query ที่ยาว, ใช้ index ตาม query ที่วัดจริง, ออกแบบ workload ให้สั้น และ retry เฉพาะ error ที่ transient ด้วย exponential backoff + jitter ตามคำแนะนำ (D1 limits, retry queries). การ retry ต้องไม่ทำให้ “สร้าง booking ซ้ำ”: ใช้ idempotency key หรือ unique request identifier ที่บันทึกและตรวจใน D1.

R2: ไฟล์ไม่ใช่แถวฐานข้อมูล

เก็บ metadata ของสินค้า/ไฟล์ใน D1 และเก็บ bytes ของรูป PDF หรือเอกสารใน R2. Worker binding ให้ Worker เรียก get/put โดยไม่ส่ง API credential ไป browser. เอกสาร R2 เตือนชัดว่า Worker ที่เปิด GET/PUT ทั้งหมดโดยไม่มี authorization จะเปิด bucket ต่อผู้ไม่หวังดี; authorization เป็นหน้าที่ของ application (R2 from Workers).

สำหรับรูปสินค้าสาธารณะ ใช้ key ที่ควบคุมได้และ route read-only หรือ public custom domain ที่ตั้งใจเปิด. สำหรับ upload ของผู้ใช้: ตรวจ authentication/authorization, ขนาด, MIME type และชื่อ key ที่สร้างจาก server; อย่าเชื่อ file name จาก browser. ถ้าต้องการ browser upload ตรง R2 ให้ Worker ออก presigned URL อายุสั้น, จำกัด operation และ Content-Type, และตั้ง CORS เฉพาะ origin ที่อนุญาต. Presigned URL คือ bearer credential—ผู้ได้ URL ใช้งานได้จนหมดอายุ; Cloudflare รองรับ GET/HEAD/PUT/DELETE แต่ไม่รองรับ POST multipart form (R2 presigned URLs).

Turnstile, Access และ secret

Turnstile เป็นชั้นป้องกัน form ไม่ใช่ login system. Browser ส่ง token พร้อม POST, Worker สร้าง request POST https://challenges.cloudflare.com/turnstile/v0/siteverify พร้อม secret และ response, ตรวจ success ก่อนเขียน D1/R2. การตรวจฝั่ง server เป็นข้อบังคับ: token อยู่ 300 วินาทีและใช้ได้ครั้งเดียว; client widget เพียงอย่างเดียวป้องกัน form ไม่ได้ (Server-side validation). เก็บ Turnstile secret ด้วย Workers secret และตรวจ hostname/action ที่คาดหวังเมื่อใช้ค่าเหล่านั้น. อย่า log token, secret หรือข้อมูลฟอร์มที่ละเอียดอ่อน.

Cloudflare Access เหมาะกับ /admin, preview หรือเครื่องมือทีม—not a replacement for customer authorization ภายใน application. Access เป็น identity-aware proxy ที่ตรวจ request ด้วย policy; self-hosted/Worker application ใช้ policy engine และ Access applications เป็น deny-by-default จนผู้ใช้ match Allow policy (Access web apps, application type). หากมี origin ของตนเองที่อาจ bypass Cloudflare ต้อง validate Access token ที่ origin ด้วย; สำหรับ Worker ที่ Cloudflare host ให้ผูก Worker กับ Access app เป็นจุดป้องกันตรงไปตรงมา.

vars ใช้เฉพาะค่าที่ไม่ลับ เช่น environment label; secret ของแอป เช่น Turnstile secret หรือ API token ของบริการที่ Worker เรียก ต้องใช้ Workers Secrets. Local ใช้ .dev.vars หรือ .env (เลือกหนึ่งแบบ) และ ignore ใน Git. ส่วน CLOUDFLARE_API_TOKEN สำหรับ deploy เก็บใน environment ของ CLI/CI ไม่ส่งเข้า Worker runtime. Cloudflare แนะนำไม่เก็บ sensitive data ใน vars; สามารถประกาศ required secret names เพื่อให้ deploy fail หากขาด secret (Workers secrets).

Delivery, operations และต้นทุน

สอนวงจร base ของ starter ก่อน: npm run db:localnpm run dev → test API/การเข้าถึง → npm run deploy:check. จากนั้นจึงเป็น production extension: เพิ่ม config/resource ของ staging → smoke test URL จริง → deploy production. แยก staging และ production, แยก secret และ D1/R2 resource ตามระดับความเสี่ยง. การ deploy static frontend ไม่ยืนยันว่า migration หรือ API ใช้ได้ จึงต้องมี smoke checklist สำหรับ POST, query, upload และ authorization.

เปิด observability.enabled; Workers Logs เก็บ invocation, custom log, error และ uncaught exception และ Cloudflare แนะนำ structured JSON เพื่อ query/filter ได้ดี. เลือก head_sampling_rate เพื่อควบคุมปริมาณข้อมูล โดยเฉพาะ production traffic; metrics มี request/error rate, CPU/wall time และ duration (Workers Logs, Observability). Log event ควรมี requestId, route, status, duration และ error class โดยตัด email, token, cookie, body และ secret ออก.

ก่อน release ที่เสี่ยง: ดู version ที่ active, backup/export D1 ตามแผน, ทำ migration ที่ forward-compatible, และเตรียม rollback code. wrangler rollback เปลี่ยน Worker version ได้ แต่ไม่ย้อน D1/R2 schema/data โดยอัตโนมัติ และ Cloudflare ระบุว่า rollback ใช้ไม่ได้หาก resource ถูกลบหรือแก้ไม่เข้ากันระหว่าง version (Rollbacks). จึงออกแบบ migration แบบ expand → deploy code ที่อ่านได้ทั้งสอง schema → backfill → contract ภายหลัง ไม่ใช่ deploy destructive change พร้อมกัน.

ตัวเลข quota/pricing เปลี่ยนได้ ให้ผู้เรียนเปิดหน้า pricing/limits ของแผนตัวเองก่อนเปิด production. สิ่งที่ต้อง track เป็นตัวชี้วัด ได้แก่ Worker request/CPU/subrequest, D1 rows read/write/storage, R2 storage/Class A/Class B operations และ log volume. ตั้ง CPU limit เพื่อกัน runaway cost/denial-of-wallet ตามคำแนะนำของ Workers pricing และทำ budget/alert ใน account. แหล่งจริงคือ Workers pricing, Workers limits, D1 pricing และ R2 pricing; ไม่ให้ hard-code ตัวเลขในสไลด์เพราะแผนและราคาอาจเปลี่ยน.

ลำดับแนะนำในหน่วยเรียน 8 ชั่วโมง

ขั้นตอนรับรองตัวตนก่อน deploy อยู่ใน Lab Wrangler login และ API token แยก token ที่ CLI/CI ใช้จัดการ Cloudflare ออกจาก secret ที่ application ใช้ขณะรัน: CLOUDFLARE_API_TOKEN เป็น credential ของเครื่องมือ deploy จึงไม่ใส่ใน frontend หรือส่งเป็น Worker runtime secret

กำหนดการ canonical อยู่ที่ คู่มือผู้สอน 2 วัน / 8 ชั่วโมง: วัน 1 ครอบคลุม brief/skills/design/company และวัน 2 เลือก rental/D1, motion/quote overview, deploy boundaries และ capstone vertical slice. Operations เชิงลึกกับ R2 เป็นเนื้อหา optional/self-study หลังเส้นทาง Worker + D1 ไม่ใช่เงื่อนไขของ capstone ทุกคน.

เอกสารนี้เป็นฐานให้บทเรียน 08 Cloudflare deployment และ 09 production operations. นอกเหนือจาก Cloudflare ให้กลับไปใช้ checklist ของหลักสูตรสำหรับ UX, accessibility, legal/privacy, payment provider และ review โค้ดที่ AI สร้าง.

ความคืบหน้าบันทึกเฉพาะเบราว์เซอร์นี้ ไม่มีบัญชีผู้เรียนหรือการส่งข้อมูลการเรียนขึ้นเซิร์ฟเวอร์