Пошук уроків, статей та іншого контенту
Отримуйте URL, параметри, cookies і headers із контексту вхідного запиту на сервері.
У App Router серверні компоненти та Route Handlers можуть отримувати дані поточного HTTP-запиту:
параметри маршруту;
query-параметри з URL;
cookies;
HTTP-заголовки;
URL і метод запиту в Route Handler.
Ці дані доступні на сервері. Не потрібно передавати їх із клієнта через додаткові запити або зберігати в глобальному стані.
Приклади нижче використовують сучасний асинхронний API Next.js:
params,searchParams,headers()іcookies()потрібно обробляти черезawait.
Динамічні сегменти маршруту передаються сторінці через властивість params.
Структура файлів:
app/
└── products/
└── [id]/
└── page.tsxДля URL /products/42 значення params.id буде рівним "42".
type ProductPageProps = {
params: Promise<{
id: string;
}>;
};
export default async function ProductPage({
params,
}: ProductPageProps) {
const { id } = await params;
return (
<main>
<h1>Товар {id}</h1>
</main>
);
}Параметри маршруту завжди мають тип string, навіть якщо в URL передано число. Якщо значення має бути числом, його потрібно перетворити самостійно:
const productId = Number(id);
if (!Number.isInteger(productId)) {
// Обробка некоректного ідентифікатора
}Для маршруту:
app/
└── blog/
└── [category]/
└── [slug]/
└── page.tsxпараметри матимуть відповідний вигляд:
type ArticlePageProps = {
params: Promise<{
category: string;
slug: string;
}>;
};
export default async function ArticlePage({
params,
}: ArticlePageProps) {
const { category, slug } = await params;
return (
<article>
<p>Категорія: {category}</p>
<h1>Стаття: {slug}</h1>
</article>
);
}Для URL /blog/javascript/promises:
category = "javascript"
slug = "promises"Query-параметри передаються сторінці через searchParams.
Для URL:
/products/42?color=red&page=2значення можна отримати так:
type ProductPageProps = {
params: Promise<{
id: string;
}>;
searchParams: Promise<{
color?: string;
page?: string;
}>;
};
export default async function ProductPage({
params,
searchParams,
}: ProductPageProps) {
const { id } = await params;
const { color, page } = await searchParams;
return (
<main>
<h1>Товар {id}</h1>
<p>Колір: {color ?? "не вказано"}</p>
<p>Сторінка: {page ?? "1"}</p>
</main>
);
}searchParams може містити масив, якщо один параметр повторюється:
/products?tag=frontend&tag=nextjsТип такого значення:
type SearchParams = {
tag?: string | string[];
};Нормалізувати значення можна перед використанням:
const tags = await searchParams;
const rawTags = tags.tag;
const selectedTags = Array.isArray(rawTags)
? rawTags
: rawTags
? [rawTags]
: [];Не варто без перевірки використовувати query-параметри у SQL-запитах, командах або HTML. Це зовнішні дані, тому їх потрібно валідувати.
У серверному компоненті cookies доступні через функцію cookies з next/headers.
import { cookies } from "next/headers";
export default async function AccountPage() {
const cookieStore = await cookies();
const sessionId = cookieStore.get("session_id")?.value;
const language = cookieStore.get("language")?.value ?? "uk";
return (
<main>
<p>Мова: {language}</p>
<p>
{sessionId ? "Сесію знайдено" : "Користувач не авторизований"}
</p>
</main>
);
}Основні методи cookie-сховища:
get(name) — отримати одну cookie;
getAll() — отримати всі cookies із заданим іменем або всі доступні;
has(name) — перевірити наявність;
toString() — отримати cookies у текстовому форматі.
У серверному компоненті cookies призначені для читання. Наприклад, сторінка може прочитати ідентифікатор сесії, а потім отримати користувача з бази даних.
Значення cookie не слід вважати безпечним лише тому, що його встановив ваш застосунок. Сервер повинен перевіряти сесію або підпис cookie.
Заголовки поточного запиту доступні через headers з next/headers.
import { headers } from "next/headers";
export default async function DashboardPage() {
const headerStore = await headers();
const userAgent = headerStore.get("user-agent");
const requestId = headerStore.get("x-request-id");
return (
<main>
<h1>Панель керування</h1>
<p>User-Agent: {userAgent ?? "невідомо"}</p>
<p>Request ID: {requestId ?? "не передано"}</p>
</main>
);
}Для заголовків важливо враховувати, що:
назви заголовків нечутливі до регістру;
відсутній заголовок повертає null;
отримане значення походить від клієнта або проксі, тому його не можна автоматично вважати достовірним.
Наприклад, user-agent зручно використовувати для логування, але не для надійної авторизації.
Сторінка отримує окремі частини URL через params і searchParams. У Route Handler доступний сам об’єкт запиту.
Файл:
app/api/products/route.tsПриклад:
import { NextResponse } from "next/server";
export async function GET(request: Request) {
const url = new URL(request.url);
const category = url.searchParams.get("category");
const page = url.searchParams.get("page") ?? "1";
const response = {
method: request.method,
pathname: url.pathname,
category,
page,
userAgent: request.headers.get("user-agent"),
};
return NextResponse.json(response);
}Запит:
GET /api/products?category=books&page=2матиме приблизно таку відповідь:
{
"method": "GET",
"pathname": "/api/products",
"category": "books",
"page": "2",
"userAgent": "..."
}У Route Handler можна використовувати стандартний Request, оскільки його url, headers, method і cookies доступні через стандартний API.
У Next.js також можна використовувати NextRequest. Він має додаткову властивість nextUrl:
import { NextRequest, NextResponse } from "next/server";
export function GET(request: NextRequest) {
const pathname = request.nextUrl.pathname;
const page = request.nextUrl.searchParams.get("page") ?? "1";
const sessionId = request.cookies.get("session_id")?.value;
return NextResponse.json({
pathname,
page,
hasSession: Boolean(sessionId),
});
}request.nextUrl зручно використовувати для доступу до:
pathname;
searchParams;
origin;
інших частин URL, представлених об’єктом NextURL.
Нижче сторінка використовує всі основні частини контексту:
id із динамічного сегмента;
filter із query-параметра;
session_id із cookie;
user-agent і host із заголовків.
import { cookies, headers } from "next/headers";
type ProductPageProps = {
params: Promise<{
id: string;
}>;
searchParams: Promise<{
filter?: string;
}>;
};
export default async function ProductPage({
params,
searchParams,
}: ProductPageProps) {
const { id } = await params;
const { filter } = await searchParams;
const headerStore = await headers();
const cookieStore = await cookies();
const sessionId = cookieStore.get("session_id")?.value;
const userAgent = headerStore.get("user-agent");
const host = headerStore.get("host");
const productId = Number(id);
if (!Number.isInteger(productId) || productId <= 0) {
return <p>Некоректний ідентифікатор товару</p>;
}
return (
<main>
<h1>Товар {productId}</h1>
<dl>
<dt>Фільтр</dt>
<dd>{filter ?? "не задано"}</dd>
<dt>Сесія</dt>
<dd>{sessionId ? "активна" : "відсутня"}</dd>
<dt>Хост</dt>
<dd>{host ?? "невідомо"}</dd>
<dt>Браузер</dt>
<dd>{userAgent ?? "невідомо"}</dd>
</dl>
</main>
);
}Використання cookies() або headers() означає, що результат сторінки залежить від конкретного запиту. Така сторінка не може мати однаковий HTML для всіх відвідувачів.
Це важливо, коли сторінка використовує:
cookie авторизованого користувача;
заголовки мови;
заголовки для персоналізації;
інші значення, унікальні для запиту.
Параметри маршруту та query-параметри також потрібно обробляти як дані поточного URL, а не як глобальний стан застосунку.
params без awaitУ сучасному Next.js params у серверній сторінці є промісом:
const { id } = await params;Замість:
const { id } = params;headers() або cookies() без awaitПравильний варіант:
const headerStore = await headers();
const cookieStore = await cookies();paramsparams містить лише динамічні сегменти шляху. Для URL /products/42?sort=price:
params.id; // "42"
searchParams.sort; // "price"Query-параметри можуть бути відсутні:
const { page } = await searchParams;
const currentPage = page ?? "1";Перед використанням числових значень їх потрібно перевіряти та перетворювати.
Наявність session_id ще не означає, що сесія дійсна. Сервер повинен перевірити значення через сховище сесій або інший механізм авторизації.
Заголовки, як-от user-agent, referer або x-forwarded-for, можуть бути відсутніми чи зміненими проксі. Використовуйте їх лише для задач, де така точність достатня.
params містить динамічні сегменти маршруту.
searchParams містить query-параметри URL.
cookies() з next/headers читає cookies поточного запиту.
headers() з next/headers читає HTTP-заголовки.
У Route Handler URL і метод доступні через Request.
NextRequest надає зручні властивості nextUrl і cookies.
Дані запиту потрібно перевіряти, оскільки вони надходять із зовнішнього середовища.
Для сучасного API Next.js асинхронні значення потрібно отримувати через await.