العربية

دليل شامل لإجراءات الخادم في Next.js 14، يغطي أفضل الممارسات لمعالجة النماذج، والتحقق من صحة البيانات، والاعتبارات الأمنية، والتقنيات المتقدمة لبناء تطبيقات الويب الحديثة.

إجراءات الخادم في Next.js 14: إتقان أفضل الممارسات لمعالجة النماذج

يقدم Next.js 14 ميزات قوية لبناء تطبيقات ويب عالية الأداء وسهلة الاستخدام. من بين هذه الميزات، تبرز إجراءات الخادم (Server Actions) كطريقة تحويلية لمعالجة عمليات إرسال النماذج وتعديلات البيانات مباشرة على الخادم. يقدم هذا الدليل نظرة شاملة على إجراءات الخادم في Next.js 14، مع التركيز على أفضل الممارسات لمعالجة النماذج، والتحقق من صحة البيانات، والأمان، والتقنيات المتقدمة. سنستكشف أمثلة عملية ونقدم رؤى قابلة للتنفيذ لمساعدتك في بناء تطبيقات ويب قوية وقابلة للتطوير.

ما هي إجراءات الخادم في Next.js؟

إجراءات الخادم هي دوال غير متزامنة تعمل على الخادم ويمكن استدعاؤها مباشرة من مكونات React. إنها تلغي الحاجة إلى مسارات API التقليدية للتعامل مع عمليات إرسال النماذج وتعديلات البيانات، مما يؤدي إلى تبسيط الكود، وتحسين الأمان، وتعزيز الأداء. إجراءات الخادم هي مكونات خادم React (RSCs)، مما يعني أنها تُنفذ على الخادم، مما يؤدي إلى تحميل أسرع للصفحات الأولية وتحسين محركات البحث.

الفوائد الرئيسية لإجراءات الخادم:

إعداد مشروع Next.js 14 الخاص بك

قبل الخوض في إجراءات الخادم، تأكد من أن لديك مشروع Next.js 14 مُعدًا. إذا كنت تبدأ من الصفر، فأنشئ مشروعًا جديدًا باستخدام الأمر التالي:

npx create-next-app@latest my-next-app

تأكد من أن مشروعك يستخدم بنية دليل app للاستفادة الكاملة من مكونات وإجراءات الخادم.

معالجة النماذج الأساسية باستخدام إجراءات الخادم

لنبدأ بمثال بسيط: نموذج يرسل بيانات لإنشاء عنصر جديد في قاعدة بيانات. سنستخدم نموذجًا بسيطًا مع حقل إدخال وزر إرسال.

مثال: إنشاء عنصر جديد

أولاً، قم بتعريف دالة إجراء خادم داخل مكون React الخاص بك. ستتولى هذه الدالة منطق إرسال النموذج على الخادم.

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  // Simulate database interaction
  console.log('Creating item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate latency

  console.log('Item created successfully!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    await createItem(formData);
    setIsSubmitting(false);
  }

  return (
    
); }

شرح:

التحقق من صحة البيانات

التحقق من صحة البيانات أمر بالغ الأهمية لضمان سلامة البيانات ومنع الثغرات الأمنية. توفر إجراءات الخادم فرصة ممتازة لإجراء التحقق من جانب الخادم. يساعد هذا النهج في التخفيف من المخاطر المرتبطة بالتحقق من جانب العميل وحده.

مثال: التحقق من صحة بيانات الإدخال

قم بتعديل إجراء الخادم createItem ليشمل منطق التحقق من الصحة.

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  if (!name || name.length < 3) {
    throw new Error('Item name must be at least 3 characters long.');
  }

  // Simulate database interaction
  console.log('Creating item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate latency

  console.log('Item created successfully!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'An error occurred.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

شرح:

استخدام مكتبات التحقق من الصحة

لسيناريوهات التحقق الأكثر تعقيدًا، فكر في استخدام مكتبات التحقق من الصحة مثل:

إليك مثال باستخدام Zod:

// app/utils/validation.ts
import { z } from 'zod';

export const CreateItemSchema = z.object({
  name: z.string().min(3, 'Item name must be at least 3 characters long.'),
});
// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';
import { CreateItemSchema } from '../utils/validation';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  const validatedFields = CreateItemSchema.safeParse({ name });

  if (!validatedFields.success) {
    return { errors: validatedFields.error.flatten().fieldErrors };
  }

  // Simulate database interaction
  console.log('Creating item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate latency

  console.log('Item created successfully!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'An error occurred.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

شرح:

الاعتبارات الأمنية

تعزز إجراءات الخادم الأمان عن طريق تنفيذ الكود على الخادم، ولكن لا يزال من الضروري اتباع أفضل الممارسات الأمنية لحماية تطبيقك من التهديدات الشائعة.

منع تزوير الطلبات عبر المواقع (CSRF)

تستغل هجمات CSRF الثقة التي يمتلكها موقع الويب في متصفح المستخدم. لمنع هجمات CSRF، قم بتنفيذ آليات حماية CSRF.

يتعامل Next.js تلقائيًا مع حماية CSRF عند استخدام إجراءات الخادم. يقوم إطار العمل بإنشاء والتحقق من صحة رمز CSRF لكل عملية إرسال نموذج، مما يضمن أن الطلب ينشأ من تطبيقك.

التعامل مع مصادقة المستخدمين وتفويضهم

تأكد من أن المستخدمين المصرح لهم فقط يمكنهم تنفيذ إجراءات معينة. قم بتنفيذ آليات المصادقة والتفويض لحماية البيانات والوظائف الحساسة.

إليك مثال باستخدام NextAuth.js لحماية إجراء خادم:

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';
import { getServerSession } from 'next-auth';
import { authOptions } from '../../app/api/auth/[...nextauth]/route';

async function createItem(formData: FormData) {
  'use server'

  const session = await getServerSession(authOptions);

  if (!session) {
    throw new Error('Unauthorized');
  }

  const name = formData.get('name') as string;

  // Simulate database interaction
  console.log('Creating item:', name, 'by user:', session.user?.email);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate latency

  console.log('Item created successfully!');
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'An error occurred.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

شرح:

تنقية بيانات الإدخال

قم بتنقية بيانات الإدخال لمنع هجمات البرمجة النصية عبر المواقع (XSS). تحدث هجمات XSS عند إدخال كود ضار في موقع ويب، مما قد يعرض بيانات المستخدم أو وظائف التطبيق للخطر.

استخدم مكتبات مثل DOMPurify أو sanitize-html لتنقية المدخلات التي يقدمها المستخدم قبل معالجتها في إجراءات الخادم الخاصة بك.

التقنيات المتقدمة

الآن بعد أن قمنا بتغطية الأساسيات، دعنا نستكشف بعض التقنيات المتقدمة لاستخدام إجراءات الخادم بفعالية.

التحديثات المتفائلة

توفر التحديثات المتفائلة تجربة مستخدم أفضل عن طريق تحديث واجهة المستخدم فورًا كما لو أن الإجراء سينجح، حتى قبل أن يؤكد الخادم ذلك. إذا فشل الإجراء على الخادم، يتم إرجاع واجهة المستخدم إلى حالتها السابقة.

// app/components/UpdateItemForm.tsx
'use client';

import { useState } from 'react';

async function updateItem(id: string, formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  // Simulate database interaction
  console.log('Updating item:', id, 'with name:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate latency

  // Simulate failure (for demonstration purposes)
  const shouldFail = Math.random() < 0.5;
  if (shouldFail) {
    throw new Error('Failed to update item.');
  }

  console.log('Item updated successfully!');
  return { name }; // Return the updated name
}

export default function UpdateItemForm({ id, initialName }: { id: string; initialName: string }) {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  const [itemName, setItemName] = useState(initialName);

  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);

    // Optimistically update the UI
    const newName = formData.get('name') as string;
    setItemName(newName);

    try {
      const result = await updateItem(id, formData);
      //If success then update is already reflected in UI through setItemName

    } catch (error: any) {
      setErrorMessage(error.message || 'An error occurred.');
      // Revert the UI on error
      setItemName(initialName);
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    

Current Name: {itemName}

{errorMessage &&

{errorMessage}

}
); }

شرح:

إعادة التحقق من صحة البيانات

بعد أن يقوم إجراء خادم بتعديل البيانات، قد تحتاج إلى إعادة التحقق من صحة البيانات المخزنة مؤقتًا لضمان أن واجهة المستخدم تعكس أحدث التغييرات. يوفر Next.js عدة طرق لإعادة التحقق من صحة البيانات:

إليك مثال على إعادة التحقق من مسار بعد إنشاء عنصر جديد:

// app/components/CreateItemForm.tsx
'use client';

import { useState } from 'react';
import { revalidatePath } from 'next/cache';

async function createItem(formData: FormData) {
  'use server'

  const name = formData.get('name') as string;

  // Simulate database interaction
  console.log('Creating item:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate latency

  console.log('Item created successfully!');

  revalidatePath('/items'); // Revalidate the /items path
}

export default function CreateItemForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  
  async function handleSubmit(formData: FormData) {
    setIsSubmitting(true);
    setErrorMessage(null);
    try {
      await createItem(formData);
    } catch (error: any) {
      setErrorMessage(error.message || 'An error occurred.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

شرح:

أفضل الممارسات لإجراءات الخادم

لتحقيق أقصى استفادة من إجراءات الخادم، ضع في اعتبارك أفضل الممارسات التالية:

الأخطاء الشائعة وكيفية تجنبها

بينما توفر إجراءات الخادم مزايا عديدة، هناك بعض الأخطاء الشائعة التي يجب الانتباه إليها:

الخاتمة

توفر إجراءات الخادم في Next.js 14 طريقة قوية وفعالة لمعالجة عمليات إرسال النماذج وتعديلات البيانات مباشرة على الخادم. باتباع أفضل الممارسات الموضحة في هذا الدليل، يمكنك بناء تطبيقات ويب قوية وآمنة وعالية الأداء. احتضن إجراءات الخادم لتبسيط الكود الخاص بك، وتعزيز الأمان، وتحسين تجربة المستخدم الإجمالية. بينما تدمج هذه المبادئ، فكر في التأثير العالمي لخياراتك التطويرية. تأكد من أن نماذجك وعمليات معالجة البيانات الخاصة بك سهلة الوصول وآمنة وسهلة الاستخدام لجماهير دولية متنوعة. هذا الالتزام بالشمولية لن يحسن فقط من قابلية استخدام تطبيقك، بل سيوسع أيضًا من نطاقه وفعاليته على نطاق عالمي.