Avatar ·

Как правильно закодировать URL в JavaScript? encodeURI vs encodeURIComponent

Всем привет! Я новичок в JavaScript и столкнулся с проблемой при работе с URL. Мне нужно отправить запрос на сервер с параметрами, которые содержат специальные символы и кириллицу. Например, у меня есть строка поиска: "кофе & чай / рецепты?". Я пробовал использовать `encodeURI()`, но заметил, что некоторые символы не кодируются. Потом нашел `encodeURIComponent()`, но теперь не понимаю, какой метод когда применять. Вот пример моего кода, который не работает как ожидалось: ```javascript const baseUrl = "https://api.example.com/search"; const query = "кофе & чай / рецепты?"; const fullUrl = baseUrl + "?q=" + encodeURI(query); console.log(fullUrl); // Результат: https://api.example.com/search?q=%D0%BA%D0%BE%D1%84%D0%B5%20&%20%D1%87%D0%B0%D0%B9%20/%20%D1%80%D0%B5%D1%86%D0%B5%D0%BF%D1%82%D1%8B? // Видно, что & и ? остались не закодированы ``` Пробовал использовать `encodeURIComponent`: ```javascript const encodedQuery = encodeURIComponent(query); console.log(encodedQuery); // %D0%BA%D0%BE%D1%84%D0%B5%20%26%20%D1%87%D0%B0%D0%B9%20%2F%20%D1%80%D0%B5%D1%86%D0%B5%D0%BF%D1%82%D1%8B%3F ``` Теперь все символы закодированы, но я не уверен, что это правильно для всего URL. Подскажите, пожалуйста: 1. В чем разница между `encodeURI` и `encodeURIComponent`? 2. Когда какой метод использовать? 3. Есть ли другие способы кодирования URL в JavaScript? Заранее спасибо за помощь! <<>>

Разница между encodeURI и encodeURIComponent

Отличный вопрос! Это одна из самых частых ловушек для начинающих разработчиков. Давайте разберемся раз и навсегда.

encodeURI предназначен для кодирования целого URL. Он сохраняет символы, которые являются частью синтаксиса URI (например, ://, ?, #, /, &). Именно поэтому в вашем примере & и ? остались незакодированными — encodeURI считает их допустимыми разделителями.

encodeURIComponent предназначен для кодирования отдельных компонентов URL (например, значений параметров запроса). Он кодирует ВСЕ символы, кроме букв, цифр и -_.!~*'(). Это гарантирует, что ваше значение не будет интерпретировано как часть синтаксиса URL.

Правило простое:

  • encodeURI — для всего URL целиком (если URL уже сформирован, но содержит не-ASCII символы)
  • encodeURIComponent — для каждого значения параметра отдельно

Правильное решение вашей задачи

Вот как нужно собирать URL с параметрами:

const baseUrl = "https://api.example.com/search";
const query = "кофе & чай / рецепты?";

// Правильный подход:
// 1. Кодируем ТОЛЬКО значение параметра
const encodedQuery = encodeURIComponent(query);
// encodedQuery = "%D0%BA%D0%BE%D1%84%D0%B5%20%26%20%D1%87%D0%B0%D0%B9%20%2F%20%D1%80%D0%B5%D1%86%D0%B5%D0%BF%D1%82%D1%8B%3F"

// 2. Собираем URL
const fullUrl = baseUrl + "?q=" + encodedQuery;
// Результат: https://api.example.com/search?q=%D0%BA%D0%BE%D1%84%D0%B5%20%26%20%D1%87%D0%B0%D0%B9%20%2F%20%D1%80%D0%B5%D1%86%D0%B5%D0%BF%D1%82%D1%8B%3F

console.log(fullUrl);
// Сервер получит: ?q=кофе & чай / рецепты?
// (сервер автоматически декодирует)

Современный подход с URLSearchParams

В современном JavaScript лучше использовать URL и URLSearchParams — это безопаснее и читаемее:

const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "кофе & чай / рецепты?");
url.searchParams.set("page", "1");
url.searchParams.set("lang", "ru");

console.log(url.toString());
// https://api.example.com/search?q=%D0%BA%D0%BE%D1%84%D0%B5+%26+%D1%87%D0%B0%D0%B9+%2F+%D1%80%D0%B5%D1%86%D0%B5%D0%BF%D1%82%D1%8B%3F&page=1&lang=ru

// Обратите внимание: пробелы кодируются как + (application/x-www-form-urlencoded)

Декодирование

Для обратного преобразования используйте:

  • decodeURI() — для декодирования всего URL
  • decodeURIComponent() — для декодирования отдельных компонентов
const encoded = "%D0%BA%D0%BE%D1%84%D0%B5%20%26%20%D1%87%D0%B0%D0%B9";
console.log(decodeURIComponent(encoded)); // "кофе & чай"

Важные нюансы

  • Никогда не применяйте encodeURI к значениям параметров — это сломает URL, если в значении есть & или #
  • Не кодируйте уже закодированные значения — это приведет к двойному кодированию
  • Для отправки форм используйте new FormData() — он сам правильно кодирует данные
  • Старый метод escape() не используйте — он устарел и работает некорректно с Unicode

Запомните золотое правило: кодируйте каждую часть URL отдельно, как можно ближе к моменту её использования. Если вы собираете URL вручную — используйте encodeURIComponent для каждого параметра. Если используете URL API — он сделает всё за вас.

<<>>

Дополнительные методы и старый браузерный подход

Если вы работаете с очень старыми браузерами (IE < 10) или нужна полная совместимость, можно написать свою функцию-обертку:

function safeEncodeURIComponent(str) {
    return encodeURIComponent(str)
        .replace(/[!'()*]/g, function(c) {
            return '%' + c.charCodeAt(0).toString(16).toUpperCase();
        });
}

// Использование:
const query = "кофе & чай (рецепты)";
console.log(safeEncodeURIComponent(query));
// %D0%BA%D0%BE%D1%84%D0%B5%20%26%20%D1%87%D0%B0%D0%B9%20%28%D1%80%D0%B5%D1%86%D0%B5%D0%BF%D1%82%D1%8B%29

Также стоит упомянуть btoa() и atob() — они кодируют в Base64, но это не для URL, а для передачи бинарных данных в текстовом виде (например, для авторизации).

И еще один полезный трюк: если вы работаете с Node.js, используйте встроенный модуль querystring:

const querystring = require('querystring');
const params = { q: "кофе & чай", page: 1 };
const queryString = querystring.stringify(params);
console.log(queryString); // q=%D0%BA%D0%BE%D1%84%D0%B5%20%26%20%D1%87%D0%B0%D0%B9&page=1

Главное помните: encodeURIComponent — ваш лучший друг для значений параметров, а URLSearchParams — для современных проектов.