Menu
Русский

URL и URLSearchParams в JavaScript: парсинг URL

Разбираем, как парсить, собирать и менять URL в JavaScript через URL и URLSearchParams — без регулярок и без подводных камней с кодированием.

Хватит парсить URL строковыми трюками

До появления API URL все резали адреса через split('?'), регулярки и молитвы. Работало — ровно до того момента, пока в значении не появлялся &, =, пробел или какой-нибудь не-ASCII символ. И тут всё разваливалось. И в браузере, и в Node есть нормальный парсер. Пользуйтесь им.

index.js
Output
Click Run to see the output here.

Один вызов — и весь URL уже разобран на части и корректно декодирован. При невалидном вводе конструктор бросает TypeError, и это как раз то, что нужно в большинстве случаев: мусорный URL должен падать громко, а не тихо протаскивать мусор дальше по коду.

Как получить query-параметры из URL

У каждого объекта URL есть свойство .searchParams — это объект URLSearchParams, который умеет читать и изменять query string:

index.js
Output
Click Run to see the output here.

Несколько моментов, на которые стоит обратить внимание:

  • Значения возвращаются уже декодированными. ?name=Ada%20Lovelace превратится в "Ada Lovelace".
  • Всё — это строка. "2" — это не 2. Если нужно число, преобразуйте через Number().
  • Повторяющиеся ключи — это нормально. get вернёт первое совпадение, а getAll — все.
  • Для отсутствующих ключей возвращается null, а не undefined — так что ?? "default" отлично с ними работает.

Как собрать query string в JavaScript

Собрать query-строку с нуля можно через URLSearchParams — без ручного экранирования и склейки через &:

index.js
Output
Click Run to see the output here.

А ещё его можно собрать из объекта — подойдёт любой итерируемый набор пар [ключ, значение], да и обычный объект тоже сгодится:

index.js
Output
Click Run to see the output here.

set и append: set перезаписывает уже существующее значение по этому ключу, а append добавляет ещё одно. append удобно использовать, когда ключ может законно повторяться (теги, фильтры); set — для параметров с единственным значением.

Как изменить URL

Объект URL живой, поэтому любые изменения в searchParams автоматически отражаются в .search и .href:

index.js
Output
Click Run to see the output here.

Это идиоматичный способ добавить query-параметр к уже существующему URL. Не нужно проверять, есть ли в URL знак ?, и ломать голову над тем, ставить & или ?.

Точно так же можно менять и другие части URL:

index.js
Output
Click Run to see the output here.

Перебор параметров

URLSearchParams — это итерируемый объект. for...of выдаёт пары [key, value], а ещё есть привычные помощники keys(), values() и entries():

index.js
Output
Click Run to see the output here.

Учти, что повторяющиеся ключи попадают в итерацию отдельными записями — сначала увидишь tag = web, затем tag = beginner. Это честное отражение того, что реально лежит в query-строке.

Если нужно по-быстрому вывести всё как обычный объект для отладки, подойдёт Object.fromEntries — правда, он схлопывает дубликаты и оставляет только последнее значение:

index.js
Output
Click Run to see the output here.

Пригодится для отладки. Но если какой-то ключ может повторяться — это уже неверный подход.

Относительные URL требуют базы

Вызов new URL("/search?q=js") сам по себе выбросит исключение — относительный путь без базы не является валидным URL. Передайте базовый адрес вторым аргументом:

index.js
Output
Click Run to see the output here.

Правила разрешения здесь те же, что браузер применяет к <a href>: ведущий / — это абсолютный путь от хоста, без слеша — относительно текущего пути, .. поднимается на уровень выше. Очень удобно, когда вы собираете URL к API из заранее заданной базы.

В браузере window.location.href — это готовая база для парсинга URL текущей страницы:

const u = new URL(window.location.href);
const page = u.searchParams.get("page") ?? "1";

Обработка невалидных URL

Конструктор URL бросает исключение на некорректных данных. С одной стороны, это удобно, с другой — значит, что при парсинге URL в JavaScript нужно оборачивать в try/catch всё, что ввёл пользователь или прислала внешняя система:

index.js
Output
Click Run to see the output here.

В современных средах также доступен метод URL.canParse(input) — булева проверка, которая избавляет от плясок с try/catch, когда нужно просто провалидировать URL:

index.js
Output
Click Run to see the output here.

Небольшой рабочий пример

Соберём всё вместе: прочитаем текущие фильтры из URL, немного их подправим и получим новый URL, на который можно перейти:

index.js
Output
Click Run to see the output here.

Передача null удаляет параметр. Любое другое значение устанавливает или перезаписывает его. Этот паттерн вы так или иначе будете писать каждый раз, когда делаете фильтры, пагинацию или диплинки.

Что стоит запомнить

  • new URL(string) разбирает URL на именованные части. На мусоре кидает исключение.
  • url.searchParams — это URLSearchParams, у него есть get, getAll, set, append, delete, has.
  • Кодирование происходит автоматически. Не лезьте за encodeURIComponent, если только не собираете строку руками.
  • Передавайте базовый URL вторым аргументом, чтобы разрешить относительные пути.
  • URL.canParse (или try/catch) — ваш инструмент валидации для недоверенного ввода.

Каждый раз, когда рука тянется разбить URL через .split('?') или выдернуть query-параметр регуляркой, берите вместо этого встроенные API. Код короче, работает корректно, и всё это уже есть в рантайме.

Часто задаваемые вопросы

Как распарсить URL в JavaScript?

Передайте строку в конструктор URL: const u = new URL('https://example.com/path?x=1'). У полученного объекта есть свойства protocol, host, pathname, search, hash и удобный searchParams. На невалидной строке конструктор кидает исключение, так что при разборе внешних данных оборачивайте вызов в try/catch.

Как получить значение query-параметра?

Через url.searchParams.get('name') — вернётся уже декодированное значение или null, если параметра нет. Если параметр может повторяться (?tag=a&tag=b), используйте searchParams.getAll('tag') — получите массив всех значений.

Чем URL отличается от URLSearchParams?

URL описывает весь адрес целиком — протокол, хост, путь, query, хэш. URLSearchParams отвечает только за query-строку и может использоваться отдельно, чтобы собрать или разобрать что-то вроде a=1&b=2. При этом у каждого экземпляра URL есть свойство .searchParams — это как раз URLSearchParams, привязанный к этому URL.

Нужно ли кодировать параметры вручную?

Нет. URLSearchParams сам кодирует ключи и значения при вызове set, append и при сериализации в строку. Пробелы, &, =, Unicode — всё обрабатывается корректно. encodeURIComponent имеет смысл только если вы зачем-то собираете URL руками по кусочкам, а этого лучше не делать.

Учитесь программировать с Coddy

НАЧАТЬ