معالجات المسارات (Route Handlers)
تسمح لك معالجات المسارات (Route Handlers) بإنشاء معالجات طلبات مخصصة لمسار معين باستخدام واجهات Request و Response من الويب.

معلومة مفيدة: معالجات المسارات متاحة فقط داخل دليل
app
. وهي تعادل مسارات API داخل دليلpages
، مما يعني أنك لا تحتاج إلى استخدام مسارات API ومعالجات المسارات معًا.
الاصطلاح
يتم تعريف معالجات المسارات في ملف route.js|ts
داخل دليل app
:
export async function GET(request: Request) {}
export async function GET(request) {}
يمكن تداخل معالجات المسارات في أي مكان داخل دليل app
، على غرار page.js
و layout.js
. ولكن لا يمكن وجود ملف route.js
في نفس مستوى مقطع المسار مثل page.js
.
طرق HTTP المدعومة
يتم دعم طرق HTTP التالية: GET
, POST
, PUT
, PATCH
, DELETE
, HEAD
, و OPTIONS
. إذا تم استدعاء طريقة غير مدعومة، سترجع Next.js ردًا بـ 405 Method Not Allowed
.
واجهات NextRequest
و NextResponse
الممتدة
بالإضافة إلى دعم واجهات Request و Response الأصلية، تقوم Next.js بتمديدها باستخدام NextRequest
و NextResponse
لتوفير أدوات مساعدة ملائمة لحالات الاستخدام المتقدمة.
السلوك
التخزين المؤقت
لا يتم تخزين معالجات المسارات مؤقتًا افتراضيًا. ومع ذلك، يمكنك اختيار التخزين المؤقت لطرق GET
. لا يتم تخزين طرق HTTP الأخرى المدعومة مؤقتًا. لتخزين طريقة GET
مؤقتًا، استخدم خيار تكوين المسار مثل export const dynamic = 'force-static'
في ملف معالج المسار.
export const dynamic = 'force-static'
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
})
const data = await res.json()
return Response.json({ data })
}
export const dynamic = 'force-static'
export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
})
const data = await res.json()
return Response.json({ data })
}
معلومة مفيدة: لا يتم تخزين طرق HTTP الأخرى المدعومة مؤقتًا، حتى لو كانت موجودة بجوار طريقة
GET
التي يتم تخزينها مؤقتًا، في نفس الملف.
معالجات المسارات الخاصة
تبقى معالجات المسارات الخاصة مثل sitemap.ts
، وopengraph-image.tsx
، وicon.tsx
، وملفات البيانات الوصفية الأخرى ثابتة افتراضيًا ما لم تستخدم واجهات API الديناميكية أو خيارات التكوين الديناميكية.
تحليل المسار
يمكنك اعتبار route
كأدنى مستوى من بديهيات التوجيه.
- لا تشارك في التخطيطات أو التنقلات من جانب العميل مثل
page
. - لا يمكن وجود ملف
route.js
في نفس المسار مثلpage.js
.
الصفحة | المسار | النتيجة |
---|---|---|
app/page.js | app/route.js | تعارض |
app/page.js | app/api/route.js | صالح |
app/[user]/page.js | app/api/route.js | صالح |
يأخذ كل ملف route.js
أو page.js
جميع أفعال HTTP لذلك المسار.
export default function Page() {
return <h1>Hello, Next.js!</h1>
}
// ❌ تعارض
// `app/route.ts`
export async function POST(request: Request) {}
export default function Page() {
return <h1>Hello, Next.js!</h1>
}
// ❌ تعارض
// `app/route.js`
export async function POST(request) {}
أمثلة
توضح الأمثلة التالية كيفية دمج معالجات المسارات مع واجهات وميزات Next.js الأخرى.
إعادة التحقق من البيانات المخزنة مؤقتًا
يمكنك إعادة التحقق من البيانات المخزنة مؤقتًا باستخدام التوليد الثابت التدريجي (ISR):
export const revalidate = 60
export async function GET() {
const data = await fetch('https://api.vercel.app/blog')
const posts = await data.json()
return Response.json(posts)
}
export const revalidate = 60
export async function GET() {
const data = await fetch('https://api.vercel.app/blog')
const posts = await data.json()
return Response.json(posts)
}
ملفات تعريف الارتباط (Cookies)
يمكنك قراءة أو تعيين ملفات تعريف الارتباط باستخدام cookies
من next/headers
. يمكن استدعاء هذه الوظيفة الخادمية مباشرة في معالج المسار، أو تداخلها داخل وظيفة أخرى.
بدلاً من ذلك، يمكنك إرجاع رد Response
جديد باستخدام رأس Set-Cookie
.
import { cookies } from 'next/headers'
export async function GET(request: Request) {
const cookieStore = await cookies()
const token = cookieStore.get('token')
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token.value}` },
})
}
import { cookies } from 'next/headers'
export async function GET(request) {
const cookieStore = await cookies()
const token = cookieStore.get('token')
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token}` },
})
}
يمكنك أيضًا استخدام واجهات الويب الأساسية لقراءة ملفات تعريف الارتباط من الطلب (NextRequest
):
import { type NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const token = request.cookies.get('token')
}
export async function GET(request) {
const token = request.cookies.get('token')
}
الرؤوس (Headers)
يمكنك قراءة الرؤوس باستخدام headers
من next/headers
. يمكن استدعاء هذه الوظيفة الخادمية مباشرة في معالج المسار، أو تداخلها داخل وظيفة أخرى.
هذا المثال من headers
للقراءة فقط. لتعيين الرؤوس، تحتاج إلى إرجاع رد Response
جديد برؤوس جديدة.
import { headers } from 'next/headers'
export async function GET(request: Request) {
const headersList = await headers()
const referer = headersList.get('referer')
return new Response('Hello, Next.js!', {
status: 200,
headers: { referer: referer },
})
}
import { headers } from 'next/headers'
export async function GET(request) {
const headersList = await headers()
const referer = headersList.get('referer')
return new Response('Hello, Next.js!', {
status: 200,
headers: { referer: referer },
})
}
يمكنك أيضًا استخدام واجهات الويب الأساسية لقراءة الرؤوس من الطلب (NextRequest
):
import { type NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const requestHeaders = new Headers(request.headers)
}
export async function GET(request) {
const requestHeaders = new Headers(request.headers)
}
إعادة التوجيه (Redirects)
import { redirect } from 'next/navigation'
export async function GET(request: Request) {
redirect('https://nextjs.org/')
}
import { redirect } from 'next/navigation'
export async function GET(request) {
redirect('https://nextjs.org/')
}
مقاطع المسار الديناميكية
يمكن لمعالجات المسارات استخدام المقاطع الديناميكية لإنشاء معالجات طلبات من البيانات الديناميكية.
export async function GET(
request: Request,
{ params }: { params: Promise<{ slug: string }> }
) {
const { slug } = await params // 'a', 'b', أو 'c'
}
export async function GET(request, { params }) {
const { slug } = await params // 'a', 'b', أو 'c'
}
المسار | مثال URL | params |
---|---|---|
app/items/[slug]/route.js | /items/a | Promise<{ slug: 'a' }> |
app/items/[slug]/route.js | /items/b | Promise<{ slug: 'b' }> |
app/items/[slug]/route.js | /items/c | Promise<{ slug: 'c' }> |
معلمات استعلام URL
كائن الطلب الممرر إلى معالج المسار هو مثيل NextRequest
، والذي يتضمن بعض الطرق الملائمة الإضافية، مثل تلك الخاصة بمعالجة معلمات الاستعلام بسهولة أكبر.
import { type NextRequest } from 'next/server'
export function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('query')
// query هو "hello" لـ /api/search?query=hello
}
export function GET(request) {
const searchParams = request.nextUrl.searchParams
const query = searchParams.get('query')
// query هو "hello" لـ /api/search?query=hello
}
البث (Streaming)
يُستخدم البث عادةً بالاشتراك مع نماذج اللغة الكبيرة (LLMs)، مثل OpenAI، للمحتوى الذي تم إنشاؤه بواسطة الذكاء الاصطناعي. تعرف على المزيد حول AI SDK.
import { openai } from '@ai-sdk/openai'
import { StreamingTextResponse, streamText } from 'ai'
export async function POST(req: Request) {
const { messages } = await req.json()
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
})
return new StreamingTextResponse(result.toAIStream())
}
import { openai } from '@ai-sdk/openai'
import { StreamingTextResponse, streamText } from 'ai'
export async function POST(req) {
const { messages } = await req.json()
const result = await streamText({
model: openai('gpt-4-turbo'),
messages,
})
return new StreamingTextResponse(result.toAIStream())
}
تستخدم هذه التجريدات واجهات الويب لإنشاء دفق. يمكنك أيضًا استخدام واجهات الويب الأساسية مباشرة.
// https://developer.mozilla.org/docs/Web/API/ReadableStream#convert_async_iterator_to_stream
function iteratorToStream(iterator: any) {
return new ReadableStream({
async pull(controller) {
const { value, done } = await iterator.next()
if (done) {
controller.close()
} else {
controller.enqueue(value)
}
},
})
}
function sleep(time: number) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
const encoder = new TextEncoder()
async function* makeIterator() {
yield encoder.encode('<p>One</p>')
await sleep(200)
yield encoder.encode('<p>Two</p>')
await sleep(200)
yield encoder.encode('<p>Three</p>')
}
export async function GET() {
const iterator = makeIterator()
const stream = iteratorToStream(iterator)
return new Response(stream)
}
// https://developer.mozilla.org/docs/Web/API/ReadableStream#convert_async_iterator_to_stream
function iteratorToStream(iterator) {
return new ReadableStream({
async pull(controller) {
const { value, done } = await iterator.next()
if (done) {
controller.close()
} else {
controller.enqueue(value)
}
},
})
}
function sleep(time) {
return new Promise((resolve) => {
setTimeout(resolve, time)
})
}
const encoder = new TextEncoder()
async function* makeIterator() {
yield encoder.encode('<p>One</p>')
await sleep(200)
yield encoder.encode('<p>Two</p>')
await sleep(200)
yield encoder.encode('<p>Three</p>')
}
export async function GET() {
const iterator = makeIterator()
const stream = iteratorToStream(iterator)
return new Response(stream)
}
جسم الطلب (Request Body)
يمكنك قراءة جسم Request
باستخدام طرق واجهة الويب القياسية:
export async function POST(request: Request) {
const res = await request.json()
return Response.json({ res })
}
export async function POST(request) {
const res = await request.json()
return Response.json({ res })
}
بيانات النموذج (FormData) لجسم الطلب
يمكنك قراءة FormData
باستخدام الدالة request.formData()
:
export async function POST(request: Request) {
const formData = await request.formData()
const name = formData.get('name')
const email = formData.get('email')
return Response.json({ name, email })
}
export async function POST(request) {
const formData = await request.formData()
const name = formData.get('name')
const email = formData.get('email')
return Response.json({ name, email })
}
بما أن بيانات formData
كلها سلاسل نصية، فقد ترغب في استخدام zod-form-data
للتحقق من صحة الطلب واسترداد البيانات بالتنسيق الذي تفضله (مثل number
).
CORS
يمكنك تعيين رؤوس CORS لمعالج مسار معين باستخدام طرق واجهة الويب القياسية:
export async function GET(request: Request) {
return new Response('Hello, Next.js!', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
export async function GET(request) {
return new Response('Hello, Next.js!', {
status: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
معلومة مفيدة:
- لإضافة رؤوس CORS إلى معالجات مسارات متعددة، يمكنك استخدام البرمجيات الوسيطة (Middleware) أو ملف
next.config.js
.- بدلاً من ذلك، راجع حزمة مثال CORS.
Webhooks (وِب هوكس)
يمكنك استخدام معالج المسار (Route Handler) لاستقبال وِب هوكس من خدمات الطرف الثالث:
export async function POST(request: Request) {
try {
const text = await request.text()
// Process the webhook payload
} catch (error) {
return new Response(`Webhook error: ${error.message}`, {
status: 400,
})
}
return new Response('Success!', {
status: 200,
})
}
export async function POST(request) {
try {
const text = await request.text()
// Process the webhook payload
} catch (error) {
return new Response(`Webhook error: ${error.message}`, {
status: 400,
})
}
return new Response('Success!', {
status: 200,
})
}
من الجدير بالذكر أنه على عكس مسارات واجهة برمجة التطبيقات (API Routes) مع موجه الصفحات (Pages Router)، لا تحتاج إلى استخدام bodyParser
أو أي تكوين إضافي.
ردود غير واجهة المستخدم (Non-UI Responses)
يمكنك استخدام معالجات المسار (Route Handlers) لإرجاع محتوى غير واجهة مستخدم. لاحظ أن sitemap.xml
، robots.txt
، app icons
، و open graph images جميعها مدعومة مسبقًا.
export async function GET() {
return new Response(
`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Next.js Documentation</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`,
{
headers: {
'Content-Type': 'text/xml',
},
}
)
}
export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>Next.js Documentation</title>
<link>https://nextjs.org/docs</link>
<description>The React Framework for the Web</description>
</channel>
</rss>`)
}
خيارات تكوين القطعة (Segment Config Options)
تستخدم معالجات المسار (Route Handlers) نفس تكوين قطعة المسار المستخدم في الصفحات والتخطيطات.
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
راجع مرجع واجهة برمجة التطبيقات لمزيد من التفاصيل.