Пошук уроків, статей та іншого контенту
Навчимося отримувати параметри з URL після знака питання та використовувати їх у логіці сервера.
Query-параметри — це дані в URL, які розташовані після знака питання ?.
Наприклад:
/products?category=books&limit=10У цьому URL:
category=books — параметр category зі значенням books;
limit=10 — параметр limit зі значенням 10;
символ & розділяє кілька параметрів.
Query-параметри часто використовують для:
фільтрації даних;
сортування;
пагінації;
пошуку;
Вони не є частиною шляху ресурсу. У URL:
/products?category=booksшляхом є /products, а category=books — query-параметром.
У вбудованому HTTP-сервері Node.js URL запиту доступний у властивості req.url.
Наприклад, для запиту:
/products?category=books&limit=10значення req.url буде таким:
/products?category=books&limit=10Для розбору URL зручно використовувати вбудований клас URL.
const { URL } = require('node:url');
const requestUrl = new URL(
'/products?category=books&limit=10',
'http://localhost'
);
console.log(requestUrl.pathname); // /products
console.log(requestUrl.searchParams.get('category')); // books
console.log(requestUrl.searchParams.get('limit')); // 10Другий аргумент потрібен як базова адреса. Він дозволяє Node.js коректно розібрати відносний URL із req.url.
searchParams.get()Властивість searchParams містить query-параметри URL. Метод get() повертає значення параметра за його назвою.
const url = new URL(
'/products?category=books&limit=10',
'http://localhost'
);
const category = url.searchParams.get('category');
const limit = url.searchParams.get('limit');
console.log(category); // books
console.log(limit); // 10Якщо параметра немає, get() повертає null:
const url = new URL('/products', 'http://localhost');
const category = url.searchParams.get('category');
console.log(category); // nullТому перед використанням параметра потрібно враховувати, що він може бути відсутнім.
Розглянемо сервер, який повертає товари з урахуванням параметрів:
category — категорія товарів;
limit — максимальна кількість товарів у відповіді.
const http = require('node:http');
const products = [
{ id: 1, name: 'JavaScript для початківців', category: 'books' },
{ id: 2, name: 'Мишка', category: 'electronics' },
{ id: 3, name: 'Node.js у практиці', category: 'books' },
{ id: 4, name: 'Клавіатура', category: 'electronics' }
];
const server = http.createServer((req, res) => {
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
if (requestUrl.pathname === '/products' && req.method === 'GET') {
const category = requestUrl.searchParams.get('category');
const limitValue = requestUrl.searchParams.get('limit');
let result = products;
if (category) {
result = result.filter((product) => product.category === category);
}
if (limitValue) {
const limit = Number(limitValue);
if (!Number.isInteger(limit) || limit < 1) {
res.writeHead(400, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({
error: 'Параметр limit має бути додатним цілим числом'
}));
return;
}
result = result.slice(0, limit);
}
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify(result));
return;
}
res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify({ error: 'Маршрут не знайдено' }));
});
server.listen(3000, () => {
console.log('Сервер запущено на http://localhost:3000');
});Після запуску сервера можна виконати такі запити:
http://localhost:3000/productsПовернуться всі товари.
http://localhost:3000/products?category=booksПовернуться лише товари з категорії books.
http://localhost:3000/products?category=books&limit=1Повернеться перший товар із категорії books.
Усі значення query-параметрів спочатку є рядками.
const url = new URL('/products?limit=10&available=true', 'http://localhost');
const limit = url.searchParams.get('limit');
const available = url.searchParams.get('available');
console.log(typeof limit); // string
console.log(typeof available); // stringНавіть якщо в URL передано число або логічне значення, Node.js отримує їх як текст:
limit=10
available=trueТому значення потрібно явно перетворити:
const limit = Number(url.searchParams.get('limit'));
const available = url.searchParams.get('available') === 'true';Для чисел бажано перевіряти результат перетворення:
const limitValue = url.searchParams.get('limit');
const limit = Number(limitValue);
if (!Number.isInteger(limit) || limit < 1) {
// Параметр має некоректне значення
}Не варто без перевірки використовувати значення від клієнта в логіці сервера.
Якщо параметр необов’язковий, для нього можна встановити значення за замовчуванням.
const url = new URL('/products', 'http://localhost');
const limit = Number(url.searchParams.get('limit') || 20);
console.log(limit); // 20У цьому прикладі, якщо limit не передано, сервер використовує значення 20.
Для складнішої логіки краще явно перевірити наявність параметра:
const limitValue = url.searchParams.get('limit');
const limit = limitValue === null ? 20 : Number(limitValue);Так легше відрізнити відсутній параметр від переданого, але некоректного значення.
Один параметр може повторюватися в URL:
/products?tag=javascript&tag=nodeМетод get() поверне лише перше значення:
const url = new URL(
'/products?tag=javascript&tag=node',
'http://localhost'
);
console.log(url.searchParams.get('tag')); // javascriptЩоб отримати всі значення, використовуйте getAll():
const tags = url.searchParams.getAll('tag');
console.log(tags); // [ 'javascript', 'node' ]Це зручно для фільтрації за кількома категоріями або тегами.
const url = new URL(
'/products?category=books&category=electronics',
'http://localhost'
);
const categories = url.searchParams.getAll('category');
console.log(categories); // [ 'books', 'electronics' ]Query-параметри можуть містити пробіли, українські літери та спеціальні символи. Такі значення передаються в URL у закодованому вигляді.
Наприклад:
/products?search=Node%20.jsURLSearchParams автоматично декодує значення:
const url = new URL(
'/products?search=Node%20.js',
'http://localhost'
);
const search = url.searchParams.get('search');
console.log(search); // Node .jsНе потрібно вручну викликати decodeURIComponent() для значень, отриманих через searchParams.get(). Вони вже декодовані.
Під час обробки запиту важливо перевіряти pathname, а не весь req.url.
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
if (requestUrl.pathname === '/products') {
// Цей код виконається для /products,
// /products?category=books і /products?limit=10
}Якщо перевіряти весь req.url, параметри впливатимуть на результат:
if (req.url === '/products') {
// Умова не виконається для /products?category=books
}Для маршрутизації використовуйте pathname, а для отримання параметрів — searchParams.
req.url як шляхуif (req.url === '/products') {
// Запит із query-параметрами не буде оброблено
}Правильніше:
const requestUrl = new URL(req.url, `http://${req.headers.host}`);
if (requestUrl.pathname === '/products') {
// Маршрут коректно обробляється з параметрами та без них
}const category = requestUrl.searchParams.get('category');
// category може дорівнювати nullПеревіряйте необов’язкові параметри перед використанням:
const category = requestUrl.searchParams.get('category');
if (category) {
// Фільтрування за категорією
}const limit = Number(requestUrl.searchParams.get('limit'));Якщо клієнт передасть limit=abc, результатом буде NaN. Перевіряйте число перед використанням у фільтрації, slice() або іншій логіці.
const limit = requestUrl.searchParams.get('limit');
console.log(limit + 1); // "101", якщо limit дорівнює "10"Оскільки limit є рядком, відбувається конкатенація. Спочатку перетворіть значення:
const limit = Number(requestUrl.searchParams.get('limit'));
console.log(limit + 1); // 11Query-параметри розташовані в URL після знака ?.
Параметри між собою розділяються символом &.
Для розбору req.url використовуйте клас URL.
Шлях запиту доступний через pathname.
Значення параметрів отримуються через searchParams.get().
Якщо параметр відсутній, get() повертає null.
Усі отримані значення спочатку є рядками.
Числа та логічні значення потрібно перетворювати й перевіряти.
Для повторюваних параметрів використовуйте getAll().
Для маршрутизації перевіряйте pathname, а не весь URL.