URL и URLSearchParams

Зачем нужно

URL API и URLSearchParams — встроенные инструменты для безопасной работы с URL-адресами и query-параметрами. Вместо ручного склеивания строк (которое ломается на спецсимволах) — надёжный API с автоматическим кодированием.

Где используется

  • Построение URL для API-запросов с параметрами
  • Парсинг текущего URL (извлечение параметров)
  • Роутинг в SPA
  • Формирование ссылок для share/redirect

Структура URL

https://user:pass@www.example.com:8080/path/page?q=search&page=2#section

protocol: https:
username: user
password: pass
hostname: www.example.com
port:     8080
host:     www.example.com:8080
pathname: /path/page
search:   ?q=search&page=2
hash:     #section
origin:   https://www.example.com:8080
href:     полный URL

URL API

// === Создание URL ===
const url = new URL('https://example.com/api/search');
url.searchParams.set('q', 'javascript');
url.searchParams.set('page', '2');
console.log(url.toString());
// https://example.com/api/search?q=javascript&page=2

// === Парсинг URL ===
const url = new URL('https://example.com:8080/api/users?role=admin&active=true#section');

url.protocol;  // 'https:'
url.hostname;  // 'example.com'
url.port;      // '8080'
url.pathname;  // '/api/users'
url.search;    // '?role=admin&active=true'
url.hash;      // '#section'
url.origin;    // 'https://example.com:8080'

// === Относительные URL ===
const base = new URL('https://example.com/api/v1/');
const users = new URL('users', base);        // https://example.com/api/v1/users
const abs = new URL('/other', base);          // https://example.com/other

// === Изменение URL ===
const url = new URL('https://example.com/old');
url.pathname = '/new';
url.searchParams.set('key', 'value');
console.log(url.href); // https://example.com/new?key=value

// === Текущий URL страницы ===
const current = new URL(window.location.href);
console.log(current.pathname);
console.log(current.searchParams.get('q'));

URLSearchParams

// === Создание ===
const params = new URLSearchParams();
params.set('q', 'javascript');
params.set('page', '2');
params.set('sort', 'date');
console.log(params.toString()); // q=javascript&page=2&sort=date

// Из строки
const params = new URLSearchParams('q=javascript&page=2');

// Из объекта
const params = new URLSearchParams({
  q: 'javascript',
  page: '2',
  sort: 'date',
});

// Из текущего URL
const params = new URLSearchParams(window.location.search);

// === Чтение ===
params.get('q');          // 'javascript'
params.get('missing');    // null
params.has('q');          // true
params.getAll('tag');     // ['js', 'web'] (если несколько значений)

// === Изменение ===
params.set('page', '3');      // Заменить значение
params.append('tag', 'js');   // Добавить (может быть несколько)
params.append('tag', 'web');
params.delete('sort');         // Удалить
params.sort();                 // Отсортировать по имени

// === Итерация ===
for (const [key, value] of params) {
  console.log(`${key} = ${value}`);
}

// В объект
const obj = Object.fromEntries(params.entries());
// { q: 'javascript', page: '3', tag: 'web' }
// Внимание: при нескольких одинаковых ключах сохранится только последний

// В массив
const arr = [...params.entries()];
// [['q', 'javascript'], ['page', '3'], ['tag', 'js'], ['tag', 'web']]

Кодирование URL

// URLSearchParams автоматически кодирует спецсимволы
const params = new URLSearchParams();
params.set('q', 'привет мир & more');
console.log(params.toString());
// q=%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82+%D0%BC%D0%B8%D1%80+%26+more

// === Ручное кодирование (когда нужно) ===
encodeURIComponent('привет мир & more');
// '%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82%20%D0%BC%D0%B8%D1%80%20%26%20more'

decodeURIComponent('%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82');
// 'привет'

// encodeURI — кодирует URL целиком (не трогает :, /, ?, #, &, =)
encodeURI('https://example.com/путь?q=привет');
// 'https://example.com/%D0%BF%D1%83%D1%82%D1%8C?q=%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D1%82'

// encodeURIComponent — кодирует значение параметра (кодирует ВСЕ спецсимволы)
encodeURIComponent('a=1&b=2');
// 'a%3D1%26b%3D2'

Практические примеры

// === Построение URL для API ===
function buildApiUrl(endpoint, params = {}) {
  const url = new URL(endpoint, 'https://api.example.com');
  Object.entries(params).forEach(([key, value]) => {
    if (value !== undefined && value !== null) {
      url.searchParams.set(key, String(value));
    }
  });
  return url.toString();
}

buildApiUrl('/users', { page: 2, limit: 10, role: 'admin' });
// 'https://api.example.com/users?page=2&limit=10&role=admin'

// === Обновление URL без перезагрузки (SPA) ===
function updateQueryParam(key, value) {
  const url = new URL(window.location.href);
  if (value) {
    url.searchParams.set(key, value);
  } else {
    url.searchParams.delete(key);
  }
  history.pushState(null, '', url.toString());
}

// Пользователь ввёл в поиск → URL обновляется
updateQueryParam('q', 'javascript');
// URL: /search?q=javascript

// === Парсинг параметров при загрузке страницы ===
function getSearchParams() {
  return Object.fromEntries(
    new URLSearchParams(window.location.search).entries()
  );
}

// URL: /products?category=electronics&sort=price&page=2
const { category, sort, page } = getSearchParams;

Частые ошибки

  1. Ручное склеиваниеurl + '?q=' + value ломается на спецсимволах (&, =, пробелы)
  2. encodeURI вместо encodeURIComponent — encodeURI не кодирует &, =, ? → параметры ломаются
  3. Забывают toStringparams.set ничего не возвращает, нужен params.toString()
  4. Object.fromEntries с дубликатами — множественные параметры (tag=a&tag=b) теряются
  5. Нет проверки nullparams.get('x') возвращает null, не undefined

Практика

  1. Распарсить URL https://shop.com/products?category=phones&brand=apple&page=2 — извлечь все параметры
  2. Построить URL для API-запроса с фильтрами из объекта
  3. Реализовать синхронизацию фильтров с URL (query params ←→ состояние)
  4. Обработать URL с кириллицей и спецсимволами

Связанные темы

Ресурсы