فارسی

راهنمای جامع اکشن‌های سرور در Next.js 14، شامل بهترین شیوه‌های مدیریت فرم، اعتبارسنجی داده‌ها، ملاحظات امنیتی و تکنیک‌های پیشرفته برای ساخت اپلیکیشن‌های وب مدرن.

اکشن‌های سرور در Next.js 14: تسلط بر بهترین شیوه‌های مدیریت فرم

Next.js 14 ویژگی‌های قدرتمندی را برای ساخت اپلیکیشن‌های وب با کارایی بالا و کاربرپسند معرفی می‌کند. در این میان، اکشن‌های سرور (Server Actions) به عنوان روشی تحول‌آفرین برای مدیریت ارسال فرم‌ها و تغییرات داده‌ها (data mutations) مستقیماً روی سرور، برجسته می‌شوند. این راهنما یک نمای کلی و جامع از اکشن‌های سرور در Next.js 14 ارائه می‌دهد و بر بهترین شیوه‌ها برای مدیریت فرم، اعتبارسنجی داده‌ها، امنیت و تکنیک‌های پیشرفته تمرکز دارد. ما مثال‌های عملی را بررسی کرده و بینش‌های کاربردی را برای کمک به شما در ساخت اپلیکیشن‌های وب قوی و مقیاس‌پذیر ارائه خواهیم داد.

اکشن‌های سرور Next.js چه هستند؟

اکشن‌های سرور توابع ناهمگامی هستند که روی سرور اجرا می‌شوند و می‌توانند مستقیماً از کامپوننت‌های ری‌اکت فراخوانی شوند. آن‌ها نیاز به مسیرهای API سنتی برای مدیریت ارسال فرم‌ها و تغییرات داده‌ها را از بین می‌برند که منجر به ساده‌سازی کد، بهبود امنیت و افزایش عملکرد می‌شود. اکشن‌های سرور، کامپوننت‌های سرور ری‌اکت (RSCs) هستند، به این معنی که روی سرور اجرا می‌شوند و منجر به بارگذاری سریع‌تر صفحات اولیه و بهبود سئو می‌شوند.

مزایای کلیدی اکشن‌های سرور:

راه‌اندازی پروژه Next.js 14 شما

قبل از پرداختن به اکشن‌های سرور، اطمینان حاصل کنید که یک پروژه Next.js 14 راه‌اندازی کرده‌اید. اگر از ابتدا شروع می‌کنید، با استفاده از دستور زیر یک پروژه جدید ایجاد کنید:

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

اطمینان حاصل کنید که پروژه شما از ساختار دایرکتوری app استفاده می‌کند تا بتوانید از مزایای کامل کامپوننت‌های سرور و اکشن‌ها بهره‌مند شوید.

مدیریت فرم پایه با اکشن‌های سرور

بیایید با یک مثال ساده شروع کنیم: فرمی که داده‌ها را برای ایجاد یک آیتم جدید در پایگاه داده ارسال می‌کند. ما از یک فرم ساده با یک فیلد ورودی و یک دکمه ارسال استفاده خواهیم کرد.

مثال: ایجاد یک آیتم جدید

ابتدا، یک تابع اکشن سرور را در کامپوننت ری‌اکت خود تعریف کنید. این تابع منطق ارسال فرم را روی سرور مدیریت خواهد کرد.

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

import { useState } from 'react';

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

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

  // شبیه‌سازی تعامل با پایگاه داده
  console.log('در حال ایجاد آیتم:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // شبیه‌سازی تأخیر

  console.log('آیتم با موفقیت ایجاد شد!');
}

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('نام آیتم باید حداقل ۳ کاراکتر باشد.');
  }

  // شبیه‌سازی تعامل با پایگاه داده
  console.log('در حال ایجاد آیتم:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // شبیه‌سازی تأخیر

  console.log('آیتم با موفقیت ایجاد شد!');
}

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 || 'خطایی رخ داد.');
    } 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, 'نام آیتم باید حداقل ۳ کاراکتر باشد.'),
});
// 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 };
  }

  // شبیه‌سازی تعامل با پایگاه داده
  console.log('در حال ایجاد آیتم:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // شبیه‌سازی تأخیر

  console.log('آیتم با موفقیت ایجاد شد!');
}

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 || 'خطایی رخ داد.');
    } 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('غیرمجاز');
  }

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

  // شبیه‌سازی تعامل با پایگاه داده
  console.log('در حال ایجاد آیتم:', name, 'توسط کاربر:', session.user?.email);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // شبیه‌سازی تأخیر

  console.log('آیتم با موفقیت ایجاد شد!');
}

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 || 'خطایی رخ داد.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

توضیح:

پاک‌سازی داده‌های ورودی

داده‌های ورودی را برای جلوگیری از حملات اسکریپت‌نویسی بین سایتی (XSS) پاک‌سازی کنید. حملات XSS زمانی رخ می‌دهند که کد مخرب به یک وب‌سایت تزریق می‌شود و به طور بالقوه داده‌های کاربر یا عملکرد اپلیکیشن را به خطر می‌اندازد.

از کتابخانه‌هایی مانند DOMPurify یا sanitize-html برای پاک‌سازی ورودی‌های ارائه‌شده توسط کاربر قبل از پردازش آن‌ها در اکشن‌های سرور خود استفاده کنید.

تکنیک‌های پیشرفته

اکنون که اصول اولیه را پوشش دادیم، بیایید برخی از تکنیک‌های پیشرفته برای استفاده مؤثر از اکشن‌های سرور را بررسی کنیم.

به‌روزرسانی‌های خوش‌بینانه (Optimistic Updates)

به‌روزرسانی‌های خوش‌بینانه با به‌روزرسانی فوری UI، طوری که انگار عمل با موفقیت انجام خواهد شد، تجربه کاربری بهتری را فراهم می‌کنند، حتی قبل از اینکه سرور آن را تأیید کند. اگر عمل در سرور با شکست مواجه شود، UI به حالت قبلی خود بازگردانده می‌شود.

// 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;

  // شبیه‌سازی تعامل با پایگاه داده
  console.log('در حال به‌روزرسانی آیتم:', id, 'با نام:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // شبیه‌سازی تأخیر

  // شبیه‌سازی شکست (برای اهداف نمایشی)
  const shouldFail = Math.random() < 0.5;
  if (shouldFail) {
    throw new Error('به‌روزرسانی آیتم با شکست مواجه شد.');
  }

  console.log('آیتم با موفقیت به‌روزرسانی شد!');
  return { 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);

    // به‌روزرسانی خوش‌بینانه UI
    const newName = formData.get('name') as string;
    setItemName(newName);

    try {
      const result = await updateItem(id, formData);
      // در صورت موفقیت، به‌روزرسانی از طریق setItemName قبلاً در UI منعکس شده است

    } catch (error: any) {
      setErrorMessage(error.message || 'خطایی رخ داد.');
      // بازگرداندن UI در صورت خطا
      setItemName(initialName);
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    

نام فعلی: {itemName}

{errorMessage &&

{errorMessage}

}
); }

توضیح:

اعتبارسنجی مجدد داده‌ها (Revalidating Data)

پس از اینکه یک اکشن سرور داده‌ها را تغییر می‌دهد، ممکن است لازم باشد داده‌های کش‌شده را مجدداً اعتبارسنجی کنید تا اطمینان حاصل شود که UI آخرین تغییرات را منعکس می‌کند. 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;

  // شبیه‌سازی تعامل با پایگاه داده
  console.log('در حال ایجاد آیتم:', name);

  await new Promise((resolve) => setTimeout(resolve, 1000)); // شبیه‌سازی تأخیر

  console.log('آیتم با موفقیت ایجاد شد!');

  revalidatePath('/items'); // اعتبارسنجی مجدد مسیر /items
}

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 || 'خطایی رخ داد.');
    } finally {
      setIsSubmitting(false);
    }
  }

  return (
    
{errorMessage &&

{errorMessage}

}
); }

توضیح:

بهترین شیوه‌ها برای اکشن‌های سرور

برای به حداکثر رساندن مزایای اکشن‌های سرور، بهترین شیوه‌های زیر را در نظر بگیرید:

اشتباهات رایج و نحوه اجتناب از آن‌ها

در حالی که اکشن‌های سرور مزایای متعددی را ارائه می‌دهند، برخی از اشتباهات رایج وجود دارد که باید از آن‌ها آگاه باشید:

نتیجه‌گیری

اکشن‌های سرور در Next.js 14 روشی قدرتمند و کارآمد برای مدیریت ارسال فرم‌ها و تغییرات داده‌ها مستقیماً روی سرور ارائه می‌دهند. با پیروی از بهترین شیوه‌های ذکر شده در این راهنما، می‌توانید اپلیکیشن‌های وب قوی، امن و با کارایی بالا بسازید. اکشن‌های سرور را برای ساده‌سازی کد، افزایش امنیت و بهبود تجربه کلی کاربر به کار بگیرید. همانطور که این اصول را ادغام می‌کنید، تأثیر جهانی انتخاب‌های توسعه خود را در نظر بگیرید. اطمینان حاصل کنید که فرم‌ها و فرآیندهای مدیریت داده شما برای مخاطبان بین‌المللی متنوع، در دسترس، امن و کاربرپسند هستند. این تعهد به فراگیری نه تنها قابلیت استفاده اپلیکیشن شما را بهبود می‌بخشد، بلکه دامنه و اثربخشی آن را در مقیاس جهانی نیز گسترش می‌دهد.