التكامل الخلفي لنموذج Next.js (جهاز توجيه التطبيق وإجراءات الخادم)
أكمل دليل تنفيذ TypeScript وReact للتعامل مع نماذج الاتصال في Next.js 14/15 باستخدام نقاط نهاية Lugatu وإجراءات الخادم دون التعرض لبيانات الاعتماد.
1. بنية جهاز التوجيه لتطبيق Next.js مع إجراءات الخادم
يتم تنفيذ إجراءات خادم Next.js حصريًا على الخادم، مما يجعلها مثالية لإرسال الاستفسارات باستخدام مفاتيح Lugatu API الخاصة دون الكشف عن الأسرار في حزم العميل.
'use server';
export async function submitContact(prevState: any, formData: FormData) {
// Silent rejection of automated bot submissions via honeypot trap
const honeypot = (formData.get('_gotcha') as string) || '';
if (honeypot) {
return { success: true, error: null };
}
const name = formData.get('name') as string;
const email = formData.get('email') as string;
const message = formData.get('message') as string;
if (!name || !email || !message) {
return { success: false, error: 'All fields are required.' };
}
const payload = {
fields: { name, email, message },
};
try {
const res = await fetch(`https://www.lugatu.com/api/v1/forms/${process.env.LUGATU_FORM_ID}/submissions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.LUGATU_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify(payload),
});
if (!res.ok) {
return { success: false, error: 'Failed to submit form.' };
}
return { success: true, error: null };
} catch (err) {
return { success: false, error: 'Network error occurred.' };
}
}
2. مكون النموذج من جانب العميل مع حالة التحميل
قم بتوصيل إجراء الخادم الخاص بك بمكون عميل React 19 / Next.js مع مؤشرات تحميل يمكن الوصول إليها.
'use client';
import { useActionState } from 'react';
import { submitContact } from '@/app/actions/contact';
export function ContactForm() {
const [state, formAction, isPending] = useActionState(submitContact, { success: false, error: null });
return (
<form action={formAction} className="space-y-4 max-w-md">
<div>
<label className="block text-sm font-semibold mb-1">Name</label>
<input name="name" required className="w-full border rounded-xl p-2.5" />
</div>
<div>
<label className="block text-sm font-semibold mb-1">Email</label>
<input type="email" name="email" required className="w-full border rounded-xl p-2.5" />
</div>
<div>
<label className="block text-sm font-semibold mb-1">Message</label>
<textarea name="message" rows={4} required className="w-full border rounded-xl p-2.5" />
</div>
<input type="text" name="_gotcha" style={{ display: 'none' }} tabIndex={-1} autoComplete="off" />
<button type="submit" disabled={isPending} className="btn-primary-editorial w-full py-2.5">
{isPending ? 'Sending...' : 'Send Message'}
</button>
{state.success && <p className="text-emerald-700 text-sm">Thank you! Your message was received.</p>}
{state.error && <p className="text-red-700 text-sm">{state.error}</p>}
</form>
);
}
الأمن والمصادقة الثابتة
تعليمات الأمان: لا تستخدم مطلقًا البادئة LUGATU_API_KEY بـ NEXT_PUBLIC_. يمكن للمتغيرات الخاصة من جانب الخادم فقط الاحتفاظ بمفتاح API المباشر الخاص بك بأمان.
استكشاف الأخطاء وإصلاحها وأخطاء العرض الشائعة
أنت تقوم بإجراء استدعاء fetch() من كود المتصفح من جانب العميل باستخدام مفتاح API. إما التبديل إلى إجراء خادم Next.js أو استخدام نقطة نهاية النموذج العام بدون مفتاح API.
الأسئلة المتداولة
هل يمكنني نشر هذا على صفحات Vercel أو Cloudflare؟
نعم. تعمل إجراءات الخادم بسلاسة عبر الأنظمة الأساسية التي لا تحتوي على خادم وأوقات تشغيل الحافة التي يدعمها Next.js.
هل أنت مستعد لإنشاء نقطة نهاية النموذج الخاص بك؟
ابدأ مجانًا في ثوانٍ. لا حاجة لبطاقة الائتمان.