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++» без ручного декодирования. Этот же приём лежит в основе гайда, как хранить фильтры в адресе страницы.
Как поймать такую ошибку за минуту
Баг с кодированием хитрый: на обычных словах всё работает, ломаются только редкие символы. Поэтому проверяй специально.
- Вбей в своё поле поиска строку-ловушку:
Tom & Jerry C++ #1 50%. В ней все опасные символы сразу. - Открой DevTools → Network и выбери отправленный запрос.
- Во вкладке 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, и вопрос закрыт.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.





