Что такое…

encodeURI или encodeURIComponent — в чём разница и почему «Tom & Jerry» ищется как «Tom»

Иллюстрация: две посылки — одна упакована наглухо, у второй из шва выпадает содержимое

Ты делаешь поиск. Пользователь вводит «Tom & Jerry», ты собираешь ссылку и аккуратно её кодируешь:

const url = encodeURI("https://site.ru/search?q=" + query);
// https://site.ru/search?q=Tom%20&%20Jerry

Пробелы стали %20, выглядит прилично. А сервер ищет просто «Tom ». И получает странный второй параметр с именем « Jerry».

Смотри, что произошло: encodeURI оставил & как есть. А & в адресе — это разделитель параметров. Ссылка развалилась на две части. Функция не сломалась — ты взял не ту.

Короткий ответ

  • encodeURI — для целого адреса. Кодирует пробелы, кириллицу и прочее «нелегальное», но оставляет символы, из которых собран сам URL: : / ? # & = + и другие.
  • encodeURIComponent — для кусочка внутри адреса: значения параметра, сегмента пути. Кодирует почти всё, включая & = + / ? #.

Правило запоминается одной фразой: вставляешь значение — кодируй компонентом. Целые адреса руками почти никто не собирает.

Аналогия: encodeURI — это упаковать уже собранный шкаф, не разбирая. encodeURIComponent — упаковать каждую деталь отдельно, чтобы ни одна не выпала по дороге.

Разница по пунктам

  • Символ &. encodeURI не трогает — и & в значении режет параметр. encodeURIComponent превращает в %26, значение доезжает целым.
  • Символ +. encodeURI("C++") даёт C++. А сервер и URLSearchParams читают + в строке запроса как пробел. Поиск «C++» превращается в «C» и два пробела. encodeURIComponent даёт C%2B%2B — и всё доходит.
  • Символ #. encodeURI оставляет его — всё после # уходит в якорь и не доходит до сервера вообще. Компонент кодирует его в %23.
  • Символ /. Для целого адреса его трогать нельзя, для значения — нужно. Имя файла отчёт/2026 без кодирования превратится в лишнюю папку.
  • Кириллица и пробелы. Обе функции кодируют одинаково: кот → %D0%BA%D0%BE%D1%82.
  • Повторное кодирование. Обе кодируют знак %. Закодировал уже закодированное — %20 стал %2520. Если видишь в логах %25 — где-то кодируют дважды.
  • Битая строка. Одиночная половинка эмодзи (например, после неудачной обрезки строки) роняет обе функции с URIError: URI malformed.

Что взять на самом деле

Честный ответ: чаще всего ни ту, ни другую руками. В современном JavaScript есть URL и URLSearchParams. Они кодируют сами и правильно:

const url = new URL("https://site.ru/search");
url.searchParams.set("q", "Tom & Jerry C++");
url.href; // https://site.ru/search?q=Tom+%26+Jerry+C%2B%2B

Заметь: пробел здесь стал +, а настоящий плюс — %2B. Это формат форм, и сервер его понимает. Перепутать уже нельзя.

Так же удобно и читать: url.searchParams.get("q") вернёт «Tom & Jerry C++» без ручного декодирования. Этот же приём лежит в основе гайда, как хранить фильтры в адресе страницы.

Как поймать такую ошибку за минуту

Баг с кодированием хитрый: на обычных словах всё работает, ломаются только редкие символы. Поэтому проверяй специально.

  1. Вбей в своё поле поиска строку-ловушку: Tom & Jerry C++ #1 50%. В ней все опасные символы сразу.
  2. Открой DevTools → Network и выбери отправленный запрос.
  3. Во вкладке Payload (или Query String Parameters) посмотри, что реально доехало. Должен быть один параметр q со всей строкой целиком.

Видишь лишний параметр — не закодирован &. Видишь «C» без плюсов — подвёл +. Строка оборвалась на #1 — остаток ушёл в якорь. А %2525 в адресе — кодируешь дважды.

Кому что подойдёт

  • Собираешь ссылку с параметрами → URL + searchParams.set. Без вариантов.
  • Подставляешь значение в путь (/users/${name}) → encodeURIComponent(name).
  • Пришёл готовый адрес с пробелами или кириллицей и его надо сделать валидным → encodeURI. Это единственный честный случай для неё. И только если адрес ещё не закодирован.
  • Старая функция escape() → не трогай. Она устарела и кодирует кириллицу в формат, который серверы не понимают.

Если сомневаешься — бери encodeURIComponent. Лишнее кодирование значения ничего не ломает, недостающее — ломает.

Почему decodeURIComponent не превращает плюс в пробел?

Потому что + как пробел — правило формата форм, а не URL вообще. decodeURIComponent("C++") вернёт «C++», а URLSearchParams — «C» с пробелами. Читай параметры тем же инструментом, которым их кодировали.

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

Да, если склеиваешь строку руками. fetch не исправит & в значении — он отправит то, что ты собрал. Передай в него URL с searchParams, и вопрос закрыт.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →