JavaScript7 мин чтения

Как декодировать URL в JavaScript (полное руководство)

В JavaScript есть функция decodeURIComponent() для декодирования отдельных компонентов URI и decodeURI() для декодирования URI целиком. Используйте try-catch для обработки некорректных URI. API URL и URLSearchParams предлагают более безопасные способы разбора URL.

decodeURIComponent() — декодирование компонента URI

decodeURIComponent() — основная функция для декодирования URL-кодированных строк в JavaScript. Она декодирует все percent-encoded последовательности, возвращая их к исходным символам. Используйте эту функцию для декодирования значений параметров запроса, сегментов пути или любого отдельного компонента URI.

// Простое декодирование
console.log(decodeURIComponent('hello%20world'));
// "hello world"

console.log(decodeURIComponent('price%3D10%26qty%3D2'));
// "price=10&qty=2"

// Декодирование символов Unicode
console.log(decodeURIComponent('caf%C3%A9'));
// "cafe" (с акцентом)

console.log(decodeURIComponent('%E4%B8%AD%E6%96%87'));
// Китайские иероглифы

// Декодирование значения параметра запроса из URL
const url = 'https://example.com/search?q=C%2B%2B%20%26%20Java';
const params = url.split('?')[1];
const value = params.split('=')[1];
console.log(decodeURIComponent(value));
// "C++ & Java"

decodeURIComponent() декодирует все percent-encoded последовательности, включая те, что соответствуют зарезервированным символам, таким как %2F (/) и %3F (?). Это правильное поведение при работе с отдельными компонентами URI, но оно может привести к проблемам, если применить функцию к URL целиком.

decodeURI() — декодирование URI целиком

decodeURI() декодирует URI целиком, сохраняя его структуру. В отличие от decodeURIComponent(), она не декодирует последовательности, представляющие зарезервированные символы URI, такие как %2F (/), %3F (?), %23 (#) и %26 (&).

// decodeURI сохраняет структуру URI
console.log(decodeURI('https://example.com/my%20page?q=hello%20world'));
// "https://example.com/my page?q=hello world"
// Пробелы декодируются, но /, ? и = сохраняются

// Сравнение с decodeURIComponent для URL целиком
console.log(decodeURIComponent('https%3A%2F%2Fexample.com%2Fpath'));
// "https://example.com/path" — корректно декодирует, если весь URL был закодирован

// decodeURI не декодирует последовательности зарезервированных символов
console.log(decodeURI('path%2Fto%2Ffile'));
// "path%2Fto%2Ffile" — %2F НЕ декодируется, потому что / зарезервирован
console.log(decodeURIComponent('path%2Fto%2Ffile'));
// "path/to/file" — %2F декодируется

Используйте decodeURI(), когда нужно сделать URL более читаемым (например, для отображения) без изменения его структуры. В большинстве же программных сценариев вам понадобится decodeURIComponent(), применяемый к отдельным компонентам.

Обработка некорректных URI

И decodeURI(), и decodeURIComponent() выбрасывают URIError, когда встречают недопустимые percent-encoded последовательности. Это происходит при одиночных знаках процента, неполных последовательностях или недопустимых байтовых последовательностях UTF-8. Всегда оборачивайте операции декодирования в блок try-catch при работе с URL, полученными от пользователя или из внешних источников.

// Эти вызовы выбрасывают URIError: URI malformed
try {
  decodeURIComponent('%');         // одиночный процент
} catch (e) {
  console.error(e.message);       // "URI malformed"
}

try {
  decodeURIComponent('%2');        // неполная последовательность
} catch (e) {
  console.error(e.message);       // "URI malformed"
}

// Функция безопасного декодирования
function safeDecode(str) {
  try {
    return decodeURIComponent(str);
  } catch (e) {
    console.warn('Failed to decode:', str);
    return str; // в случае ошибки возвращаем исходную строку
  }
}

// Исправляем некорректные percent-последовательности перед декодированием
function fixAndDecode(str) {
  // Заменяем одиночный % на %25 (закодированный знак процента)
  const fixed = str.replace(/%(?![0-9A-Fa-f]{2})/g, '%25');
  return decodeURIComponent(fixed);
}

console.log(fixAndDecode('100% complete'));
// "100% complete"

Использование API URL (рекомендуется)

Современные API URL и URLSearchParams предлагают более безопасный и структурированный способ разбора и декодирования URL. Они автоматически выполняют кодирование и декодирование, снижая риск ошибок.

// Разбираем URL и обращаемся к его компонентам (декодируются автоматически)
const url = new URL('https://example.com/path%20here?q=hello%20world&lang=en');

console.log(url.pathname);  // "/path here" (декодировано)
console.log(url.search);    // "?q=hello%20world&lang=en" (в исходном виде)

// URLSearchParams автоматически декодирует значения параметров
console.log(url.searchParams.get('q'));     // "hello world"
console.log(url.searchParams.get('lang')); // "en"

// Перебираем все параметры
for (const [key, value] of url.searchParams) {
  console.log(key, '=', value);
}
// q = hello world
// lang = en

// URLSearchParams обрабатывает + как пробел (form encoding)
const formParams = new URLSearchParams('q=hello+world&lang=en');
console.log(formParams.get('q'));  // "hello world"

// Построение URL с автоматическим кодированием
const newUrl = new URL('https://example.com/search');
newUrl.searchParams.set('q', 'C++ & Java');
newUrl.searchParams.set('page', '1');
console.log(newUrl.toString());
// "https://example.com/search?q=C%2B%2B+%26+Java&page=1"

Частые ошибки при декодировании

Ошибка 1: декодирование URL целиком с помощью decodeURIComponent(). Это может нарушить структуру URL, если он содержит закодированные зарезервированные символы. %2F в значении параметра превратится в /, что потенциально изменит смысл URL.

Ошибка 2: двойное декодирование. Если строка уже была декодирована один раз, повторное декодирование может дать неожиданный результат или ошибку. Например, строка %2520 сначала декодируется в %20, а затем в пробел. Если вы ожидаете только один уровень кодирования, двойное декодирование испортит данные.

// Проблема двойного декодирования
const encoded = '%2520'; // Это закодированный %20
console.log(decodeURIComponent(encoded));  // "%20" (верно — один уровень)
console.log(decodeURIComponent(decodeURIComponent(encoded)));  // " " (двойное декодирование!)

// Проверяем, нужно ли декодировать строку, перед её декодированием
function needsDecoding(str) {
  return str !== decodeURIComponent(str);
}

Ошибка 3: игнорирование знака +. decodeURIComponent() не преобразует + в пробелы. Если вы декодируете данные в формате form-urlencoded, нужно сначала заменить + на пробелы или использовать URLSearchParams, который делает это автоматически.

// decodeURIComponent НЕ декодирует + как пробел
console.log(decodeURIComponent('hello+world'));
// "hello+world" (а не "hello world"!)

// Решение: заменяем + перед декодированием
function decodeFormValue(str) {
  return decodeURIComponent(str.replace(/\+/g, ' '));
}
console.log(decodeFormValue('hello+world'));
// "hello world"

// Или используем URLSearchParams (обрабатывает + автоматически)
const params = new URLSearchParams('q=hello+world');
console.log(params.get('q'));
// "hello world"

Похожие статьи

Попробуйте наши бесплатные инструменты