فارسی

میدل‌ور Next.js را کاوش کنید؛ قابلیتی قدرتمند برای رهگیری و تغییر درخواست‌های ورودی. نحوه پیاده‌سازی احراز هویت، صدور مجوز، تغییر مسیر و تست A/B را با مثال‌های عملی بیاموزید.

میدل‌ور (Middleware) در Next.js: تسلط بر رهگیری درخواست‌ها برای اپلیکیشن‌های پویا

میدل‌ور Next.js روشی انعطاف‌پذیر و قدرتمند برای رهگیری و تغییر درخواست‌های ورودی قبل از رسیدن به مسیرهای شما فراهم می‌کند. این قابلیت به شما امکان می‌دهد تا طیف گسترده‌ای از ویژگی‌ها، از احراز هویت و صدور مجوز گرفته تا تغییر مسیر و تست A/B را پیاده‌سازی کنید، و همزمان عملکرد را بهینه سازید. این راهنمای جامع شما را با مفاهیم اصلی میدل‌ور Next.js آشنا کرده و نحوه استفاده مؤثر از آن را نشان می‌دهد.

میدل‌ور Next.js چیست؟

میدل‌ور در Next.js یک تابع است که قبل از تکمیل یک درخواست اجرا می‌شود. این به شما اجازه می‌دهد تا:

توابع میدل‌ور در فایل middleware.ts (یا middleware.js) در ریشه پروژه شما تعریف می‌شوند. آن‌ها برای هر مسیر در اپلیکیشن شما، یا برای مسیرهای خاص بر اساس matchers قابل تنظیم اجرا می‌شوند.

مفاهیم کلیدی و مزایا

شیء Request

شیء request اطلاعاتی درباره درخواست ورودی فراهم می‌کند، از جمله:

شیء Response

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

Matchers

Matchers به شما امکان می‌دهند مشخص کنید که میدل‌ور شما باید روی کدام مسیرها اعمال شود. شما می‌توانید matchers را با استفاده از عبارات منظم یا الگوهای مسیر تعریف کنید. این کار تضمین می‌کند که میدل‌ور شما فقط در مواقع ضروری اجرا شود و عملکرد را بهبود بخشیده و سربار را کاهش دهد.

Edge Runtime

میدل‌ور Next.js بر روی Edge Runtime اجرا می‌شود که یک محیط اجرایی سبک جاوا اسکریپت است و می‌تواند نزدیک به کاربران شما مستقر شود. این نزدیکی، تأخیر را به حداقل می‌رساند و عملکرد کلی اپلیکیشن شما را بهبود می‌بخشد، به ویژه برای کاربرانی که در سطح جهان توزیع شده‌اند. Edge Runtime در شبکه Edge Vercel و سایر پلتفرم‌های سازگار در دسترس است. Edge Runtime دارای محدودیت‌هایی است، به ویژه در استفاده از APIهای Node.js.

مثال‌های عملی: پیاده‌سازی ویژگی‌های میدل‌ور

۱. احراز هویت

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


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const token = request.cookies.get('auth_token');

 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 return NextResponse.next()
}

export const config = {
 matcher: ['/dashboard/:path*'],
}

این میدل‌ور وجود یک کوکی auth_token را بررسی می‌کند. اگر کوکی پیدا نشود، کاربر به صفحه /login هدایت می‌شود. config.matcher مشخص می‌کند که این میدل‌ور فقط باید برای مسیرهای زیر /dashboard اجرا شود.

دیدگاه جهانی: منطق احراز هویت را برای پشتیبانی از روش‌های مختلف احراز هویت (مانند OAuth, JWT) تطبیق دهید و با ارائه‌دهندگان هویت مختلف (مانند گوگل، فیسبوک، Azure AD) ادغام کنید تا به کاربران از مناطق مختلف پاسخ دهید.

۲. صدور مجوز

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


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 const token = request.cookies.get('auth_token');

 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 // مثال: دریافت نقش‌های کاربر از یک API (با منطق واقعی خود جایگزین کنید)
 const userResponse = await fetch('https://api.example.com/userinfo', {
 headers: {
 Authorization: `Bearer ${token}`,
 },
 });
 const userData = await userResponse.json();

 if (userData.role !== 'admin') {
 return NextResponse.redirect(new URL('/unauthorized', request.url))
 }

 return NextResponse.next()
}

export const config = {
 matcher: ['/admin/:path*'],
}

این میدل‌ور نقش کاربر را بازیابی کرده و بررسی می‌کند که آیا او نقش admin را دارد یا خیر. در غیر این صورت، به صفحه /unauthorized هدایت می‌شود. این مثال از یک نقطه پایانی API جایگزین استفاده می‌کند. `https://api.example.com/userinfo` را با نقطه پایانی سرور احراز هویت واقعی خود جایگزین کنید.

دیدگاه جهانی: هنگام پردازش داده‌های کاربر، به مقررات حفظ حریم خصوصی داده‌ها (مانند GDPR، CCPA) توجه داشته باشید. اقدامات امنیتی مناسب را برای محافظت از اطلاعات حساس و اطمینان از انطباق با قوانین محلی پیاده‌سازی کنید.

۳. تغییر مسیر

میدل‌ور تغییر مسیر می‌تواند برای هدایت کاربران بر اساس موقعیت مکانی، زبان یا معیارهای دیگر استفاده شود. به عنوان مثال، ممکن است کاربران را بر اساس آدرس IP آن‌ها به نسخه محلی‌سازی شده وب‌سایت خود هدایت کنید.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const country = request.geo?.country || 'US'; // اگر موقعیت‌یابی جغرافیایی ناموفق بود، به طور پیش‌فرض روی US تنظیم شود

 if (country === 'DE') {
 return NextResponse.redirect(new URL('/de', request.url))
 }

 if (country === 'FR') {
 return NextResponse.redirect(new URL('/fr', request.url))
 }

 return NextResponse.next()
}

export const config = {
 matcher: ['/'],
}

این میدل‌ور کشور کاربر را بر اساس آدرس IP او بررسی کرده و او را به نسخه محلی‌سازی شده مناسب وب‌سایت (/de برای آلمان، /fr برای فرانسه) هدایت می‌کند. اگر موقعیت‌یابی جغرافیایی ناموفق باشد، به طور پیش‌فرض به نسخه آمریکا می‌رود. توجه داشته باشید که این به در دسترس بودن پراپرتی geo بستگی دارد (مثلاً هنگام استقرار در Vercel).

دیدگاه جهانی: اطمینان حاصل کنید که وب‌سایت شما از چندین زبان و واحد پولی پشتیبانی می‌کند. به کاربران این امکان را بدهید که زبان یا منطقه ترجیحی خود را به صورت دستی انتخاب کنند. از فرمت‌های تاریخ و زمان مناسب برای هر منطقه استفاده کنید.

۴. تست A/B

میدل‌ور می‌تواند برای پیاده‌سازی تست A/B با تخصیص تصادفی کاربران به نسخه‌های مختلف یک صفحه و ردیابی رفتار آن‌ها استفاده شود. در اینجا یک مثال ساده آورده شده است:


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

function getRandomVariant() {
 return Math.random() < 0.5 ? 'A' : 'B';
}

export function middleware(request: NextRequest) {
 let variant = request.cookies.get('variant')?.value;

 if (!variant) {
 variant = getRandomVariant();
 const response = NextResponse.next();
 response.cookies.set('variant', variant);
 return response;
 }

 if (variant === 'B') {
 return NextResponse.rewrite(new URL('/variant-b', request.url));
 }

 return NextResponse.next();
}

export const config = {
 matcher: ['/'],
}

این میدل‌ور کاربران را به نسخه 'A' یا 'B' اختصاص می‌دهد. اگر کاربری از قبل کوکی variant نداشته باشد، یک کوکی به طور تصادفی به او اختصاص داده و تنظیم می‌شود. کاربرانی که به نسخه 'B' اختصاص داده شده‌اند به صفحه /variant-b بازنویسی می‌شوند. سپس شما عملکرد هر نسخه را برای تعیین اینکه کدام یک مؤثرتر است، ردیابی می‌کنید.

دیدگاه جهانی: هنگام طراحی تست‌های A/B، تفاوت‌های فرهنگی را در نظر بگیرید. آنچه در یک منطقه به خوبی کار می‌کند ممکن است در منطقه دیگر برای کاربران جذاب نباشد. اطمینان حاصل کنید که پلتفرم تست A/B شما با مقررات حریم خصوصی در مناطق مختلف سازگار است.

۵. فلگ‌های ویژگی (Feature Flags)

فلگ‌های ویژگی به شما امکان می‌دهند ویژگی‌ها را در اپلیکیشن خود بدون استقرار کد جدید فعال یا غیرفعال کنید. میدل‌ور می‌تواند برای تعیین اینکه آیا یک کاربر باید بر اساس شناسه کاربری، موقعیت مکانی یا معیارهای دیگر به یک ویژگی خاص دسترسی داشته باشد، استفاده شود.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 // مثال: دریافت فلگ‌های ویژگی از یک API
 const featureFlagsResponse = await fetch('https://api.example.com/featureflags', {
 headers: {
 'X-User-Id': 'user123',
 },
 });
 const featureFlags = await featureFlagsResponse.json();

 if (featureFlags.new_feature_enabled) {
 // فعال کردن ویژگی جدید
 return NextResponse.next();
 } else {
 // غیرفعال کردن ویژگی جدید (مثلاً، هدایت به یک صفحه جایگزین)
 return NextResponse.redirect(new URL('/alternative-page', request.url));
 }
}

export const config = {
 matcher: ['/new-feature'],
}

این میدل‌ور فلگ‌های ویژگی را از یک API دریافت کرده و بررسی می‌کند که آیا فلگ new_feature_enabled تنظیم شده است یا خیر. اگر تنظیم شده باشد، کاربر می‌تواند به صفحه /new-feature دسترسی پیدا کند. در غیر این صورت، به یک /alternative-page هدایت می‌شود.

دیدگاه جهانی: از فلگ‌های ویژگی برای عرضه تدریجی ویژگی‌های جدید به کاربران در مناطق مختلف استفاده کنید. این به شما امکان می‌دهد عملکرد را نظارت کرده و هر گونه مشکلی را قبل از انتشار ویژگی برای مخاطبان گسترده‌تر برطرف کنید. همچنین، اطمینان حاصل کنید که سیستم فلگ ویژگی شما در سطح جهانی مقیاس‌پذیر است و نتایج ثابتی را بدون توجه به موقعیت مکانی کاربر ارائه می‌دهد. محدودیت‌های نظارتی منطقه‌ای برای عرضه ویژگی‌ها را در نظر بگیرید.

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

زنجیره‌سازی میدل‌ور

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


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const response = NextResponse.next();

 // تابع میدل‌ور اول
 const token = request.cookies.get('auth_token');
 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 // تابع میدل‌ور دوم
 response.headers.set('x-middleware-custom', 'value');

 return response;
}

export const config = {
 matcher: ['/dashboard/:path*'],
}

این مثال دو میدل‌ور را در یک تابع نشان می‌دهد. اولی احراز هویت را انجام می‌دهد و دومی یک هدر سفارشی تنظیم می‌کند.

استفاده از متغیرهای محیطی

اطلاعات حساس مانند کلیدهای API و اطلاعات اتصال به پایگاه داده را به جای کدنویسی سخت در توابع میدل‌ور، در متغیرهای محیطی ذخیره کنید. این کار امنیت را بهبود می‌بخشد و مدیریت پیکربندی اپلیکیشن شما را آسان‌تر می‌کند.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const API_KEY = process.env.API_KEY;

export async function middleware(request: NextRequest) {
 const response = await fetch('https://api.example.com/data', {
 headers: {
 'X-API-Key': API_KEY,
 },
 });

 // ...
}

export const config = {
 matcher: ['/data'],
}

در این مثال، API_KEY از یک متغیر محیطی بازیابی می‌شود.

مدیریت خطا

مدیریت خطای قوی را در توابع میدل‌ور خود پیاده‌سازی کنید تا از خراب شدن اپلیکیشن شما توسط خطاهای غیرمنتظره جلوگیری شود. از بلوک‌های try...catch برای گرفتن استثناها و ثبت مناسب خطاها استفاده کنید.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 try {
 const response = await fetch('https://api.example.com/data');
 // ...
 } catch (error) {
 console.error('Error fetching data:', error);
 return NextResponse.error(); // یا به یک صفحه خطا هدایت کنید
 }
}

export const config = {
 matcher: ['/data'],
}

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

عیب‌یابی مشکلات رایج

نتیجه‌گیری

میدل‌ور Next.js ابزاری قدرتمند برای ساخت اپلیکیشن‌های وب پویا و شخصی‌سازی شده است. با تسلط بر رهگیری درخواست‌ها، می‌توانید طیف گسترده‌ای از ویژگی‌ها، از احراز هویت و صدور مجوز گرفته تا تغییر مسیر و تست A/B را پیاده‌سازی کنید. با پیروی از بهترین شیوه‌های ذکر شده در این راهنما، می‌توانید از میدل‌ور Next.js برای ایجاد اپلیکیشن‌های با کارایی بالا، امن و مقیاس‌پذیر که نیازهای کاربران جهانی شما را برآورده می‌کنند، استفاده کنید. قدرت میدل‌ور را برای باز کردن امکانات جدید در پروژه‌های Next.js خود و ارائه تجربیات کاربری استثنایی به کار بگیرید.