ไม่มีชื่อบทความ
🔐 ใช้ Next.js Server Actions / API Route บันทึกข้อมูลแทน Client เพื่อความปลอดภัย
🔎 ทำไมต้องย้าย logic ไปฝั่ง Server?
- ✅ ซ่อนข้อมูลลับ: เช่น Service Account Key ที่ไม่ควรเปิดเผยใน bundle
- 📦 ลดขนาด bundle ฝั่ง client: ไม่ต้องโหลด Firebase SDK ทั้งชุดใน browser
- 🔐 ควบคุมความปลอดภัย: ป้องกันการแก้ไข payload โดยตรงจาก client
💡 ตัวอย่าง Server Action: app/actions/saveContact.js
// app/actions/saveContact.js
'use server';
import { adminDB } from '@/lib/firebaseAdmin';
export async function saveContact(formData) {
try {
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
if (!name || !email || !message) {
throw new Error('ข้อมูลไม่ครบ');
}
await adminDB.collection('contacts').add({ name, email, message });
return { success: true };
} catch (err) {
console.error('🔥 saveContact error:', err);
return { success: false, message: err.message };
}
}
🧾 เรียกใช้จาก client component
'use client';
import { useState } from 'react';
import { saveContact } from '@/app/actions/saveContact';
export default function ContactForm() {
const [status, setStatus] = useState(null);
async function handleSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
const res = await saveContact(formData);
setStatus(res.success ? '✅ ส่งแล้ว' : `❌ ${res.message}`);
}
return (
<form onSubmit={handleSubmit}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<button type="submit">ส่ง</button>
{status && <p>{status}</p>}
</form>
);
}
⚖️ เปรียบเทียบ: Client vs Server
| ด้าน | เขียนตรงจาก Client | ใช้ Server Action / API |
|---|---|---|
| ความปลอดภัย | 🔴 เสี่ยง key รั่ว, bypass rules | ✅ ซ่อน credentials, มีการควบคุม |
| ขนาด bundle | ใหญ่ขึ้น (Firebase SDK) | เล็กลง |
| Latency | เร็วกว่า (เรียกตรง) | ช้ากว่านิด (ผ่าน server) |
| Validation | ต้องทำฝั่ง client เอง | ทำฝั่ง server ได้เลย |
🛑 ทำความเข้าใจ Error Boundary
ในกรณี Server Action ล้มเหลว เช่น throw error หรือเชื่อม Firestore ไม่ได้:
- ถ้าไม่ได้ catch → App อาจแสดงหน้า error หรือ fallback
- ควรห่อ Server Action ด้วย
try/catchแล้วส่งผลลัพธ์{ success: false, message }กลับมาให้ UI ตัดสินใจแสดงข้อความที่เหมาะสม
try {
... // save
} catch (err) {
return { success: false, message: 'เกิดข้อผิดพลาด' }
}
✅ ช่วยให้ UX ดีกว่า redirect หรือ crash ทันที
แนวทางนี้เหมาะกับฟอร์มสำคัญ เช่น สมัครสมาชิก, แบบสอบถาม, คำติชม ที่ต้องป้องกันข้อมูลปลอมจาก client และไม่ควรโหลด Firebase SDK ฝั่งเบราว์เซอร์โดยไม่จำเป็น