میدلور Next.js را کاوش کنید؛ قابلیتی قدرتمند برای رهگیری و تغییر درخواستهای ورودی. نحوه پیادهسازی احراز هویت، صدور مجوز، تغییر مسیر و تست A/B را با مثالهای عملی بیاموزید.
میدلور (Middleware) در Next.js: تسلط بر رهگیری درخواستها برای اپلیکیشنهای پویا
میدلور Next.js روشی انعطافپذیر و قدرتمند برای رهگیری و تغییر درخواستهای ورودی قبل از رسیدن به مسیرهای شما فراهم میکند. این قابلیت به شما امکان میدهد تا طیف گستردهای از ویژگیها، از احراز هویت و صدور مجوز گرفته تا تغییر مسیر و تست A/B را پیادهسازی کنید، و همزمان عملکرد را بهینه سازید. این راهنمای جامع شما را با مفاهیم اصلی میدلور Next.js آشنا کرده و نحوه استفاده مؤثر از آن را نشان میدهد.
میدلور Next.js چیست؟
میدلور در Next.js یک تابع است که قبل از تکمیل یک درخواست اجرا میشود. این به شما اجازه میدهد تا:
- رهگیری درخواستها: هدرها، کوکیها و URL درخواست ورودی را بررسی کنید.
- تغییر درخواستها: URLها را بازنویسی کنید، هدرها را تنظیم کنید یا کاربران را بر اساس معیارهای خاص تغییر مسیر دهید.
- اجرای کد: منطق سمت سرور را قبل از رندر شدن یک صفحه اجرا کنید.
توابع میدلور در فایل middleware.ts
(یا middleware.js
) در ریشه پروژه شما تعریف میشوند. آنها برای هر مسیر در اپلیکیشن شما، یا برای مسیرهای خاص بر اساس matchers قابل تنظیم اجرا میشوند.
مفاهیم کلیدی و مزایا
شیء Request
شیء request
اطلاعاتی درباره درخواست ورودی فراهم میکند، از جمله:
request.url
: URL کامل درخواست.request.method
: متد HTTP (مثلاً GET، POST).request.headers
: یک شیء حاوی هدرهای درخواست.request.cookies
: یک شیء که کوکیهای درخواست را نشان میدهد.request.geo
: در صورت وجود، دادههای موقعیت جغرافیایی مرتبط با درخواست را ارائه میدهد.
شیء Response
توابع میدلور یک شیء Response
را برای کنترل نتیجه درخواست برمیگردانند. شما میتوانید از پاسخهای زیر استفاده کنید:
NextResponse.next()
: پردازش درخواست را به طور معمول ادامه میدهد و اجازه میدهد به مسیر مورد نظر برسد.NextResponse.redirect(url)
: کاربر را به یک URL دیگر هدایت میکند.NextResponse.rewrite(url)
: URL درخواست را بازنویسی میکند و عملاً صفحه دیگری را بدون تغییر مسیر ارائه میدهد. URL در مرورگر ثابت باقی میماند.- برگرداندن یک شیء
Response
سفارشی: به شما امکان میدهد محتوای سفارشی، مانند یک صفحه خطا یا یک پاسخ JSON خاص را ارائه دهید.
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'],
}
بهترین شیوهها
- توابع میدلور را سبک نگه دارید: از انجام عملیات سنگین محاسباتی در میدلور خودداری کنید، زیرا این میتواند بر عملکرد تأثیر بگذارد. پردازش پیچیده را به وظایف پسزمینه یا سرویسهای اختصاصی منتقل کنید.
- از matchers به طور مؤثر استفاده کنید: میدلور را فقط برای مسیرهایی که به آن نیاز دارند اعمال کنید.
- میدلور خود را به طور کامل تست کنید: تستهای واحد بنویسید تا اطمینان حاصل کنید که توابع میدلور شما به درستی کار میکنند.
- عملکرد میدلور را نظارت کنید: از ابزارهای نظارتی برای ردیابی عملکرد توابع میدلور خود و شناسایی هرگونه گلوگاه استفاده کنید.
- میدلور خود را مستند کنید: هدف و عملکرد هر تابع میدلور را به وضوح مستند کنید.
- محدودیتهای Edge Runtime را در نظر بگیرید: از محدودیتهای Edge Runtime، مانند عدم وجود APIهای Node.js، آگاه باشید. کد خود را بر این اساس تنظیم کنید.
عیبیابی مشکلات رایج
- میدلور اجرا نمیشود: پیکربندی matcher خود را دوباره بررسی کنید تا اطمینان حاصل کنید که میدلور به مسیرهای صحیح اعمال میشود.
- مشکلات عملکرد: توابع میدلور کند را شناسایی و بهینه کنید. از ابزارهای پروفایلسازی برای مشخص کردن گلوگاههای عملکرد استفاده کنید.
- سازگاری با Edge Runtime: اطمینان حاصل کنید که کد شما با Edge Runtime سازگار است. از استفاده از APIهای Node.js که پشتیبانی نمیشوند خودداری کنید.
- مشکلات کوکی: بررسی کنید که کوکیها به درستی تنظیم و بازیابی میشوند. به ویژگیهای کوکی مانند
domain
،path
وsecure
توجه کنید. - تداخل هدرها: هنگام تنظیم هدرهای سفارشی در میدلور، از تداخلهای احتمالی هدر آگاه باشید. اطمینان حاصل کنید که هدرهای شما به طور ناخواسته هدرهای موجود را بازنویسی نمیکنند.
نتیجهگیری
میدلور Next.js ابزاری قدرتمند برای ساخت اپلیکیشنهای وب پویا و شخصیسازی شده است. با تسلط بر رهگیری درخواستها، میتوانید طیف گستردهای از ویژگیها، از احراز هویت و صدور مجوز گرفته تا تغییر مسیر و تست A/B را پیادهسازی کنید. با پیروی از بهترین شیوههای ذکر شده در این راهنما، میتوانید از میدلور Next.js برای ایجاد اپلیکیشنهای با کارایی بالا، امن و مقیاسپذیر که نیازهای کاربران جهانی شما را برآورده میکنند، استفاده کنید. قدرت میدلور را برای باز کردن امکانات جدید در پروژههای Next.js خود و ارائه تجربیات کاربری استثنایی به کار بگیرید.