ttools
программированиевеб-разработкаURLAPI

URL-кодирование в API: почему пробелы становятся %20

Узнайте, когда и как кодировать параметры URL, какие символы нужно экранировать и почему это критично для работы с API и веб-формами.

Вы отправляете запрос к API с параметром q=hello world, а в ответ получаете ошибку или неожиданный результат. Проблема в том, что пробел и десятки других символов нельзя использовать в URL напрямую — их нужно кодировать. Разберёмся, как работает URL-кодирование, какие символы требуют экранирования и как избежать типичных ошибок при работе с API.

Что такое URL-кодирование и зачем оно нужно

URL (Uniform Resource Locator) — это адрес ресурса в интернете. Он состоит из нескольких частей: протокола, домена, пути и параметров. Проблема в том, что стандарт URL разрешает использовать только ограниченный набор символов: латинские буквы, цифры и несколько специальных знаков вроде -, ., _, ~.

Все остальные символы — кириллица, пробелы, знаки препинания, эмодзи — нужно преобразовывать в формат, который браузер и сервер гарантированно поймут. Это и есть URL-кодирование (percent-encoding).

Каждый «запрещённый» символ заменяется на последовательность %XX, где XX — шестнадцатеричный код символа в UTF-8. Пробел имеет код 32 (или 0x20 в hex), поэтому превращается в %20. Символ # — это %23, кириллическая а%D0%B0 (два байта в UTF-8).

Какие символы требуют кодирования

Не все символы в URL нужно кодировать — зависит от того, где они находятся. В разных частях URL действуют разные правила.

Зарезервированные символы

Эти символы имеют специальное значение в URL и требуют кодирования, если вы хотите использовать их как обычный текст:

  • : — разделяет протокол и хост
  • / — разделяет части пути
  • ? — начинает строку параметров
  • # — обозначает якорь (фрагмент)
  • [ ] — для IPv6-адресов
  • @ — отделяет данные авторизации
  • ! $ & ' ( ) * + , ; = — используются в query-параметрах

Если вы хотите передать значение price=$100, то $ нужно закодировать в %24: price=%24100.

Всегда кодируем

Эти символы нельзя использовать в URL ни в каком виде:

  • Пробел → %20 (или + в query-параметрах)
  • Кириллица и другие не-ASCII символы
  • Управляющие символы (коды 0-31)
  • " < > \ ^ ` { } |

Особенности кодирования в разных частях URL

URL состоит из нескольких частей, и правила кодирования для них отличаются.

Path (путь)

В пути /api/users/Иван кириллицу нужно кодировать обязательно: /api/users/%D0%98%D0%B2%D0%B0%D0%BD. Пробелы тоже: /hello world/hello%20world.

const userId = 'Иван Петров';
const path = `/api/users/${encodeURIComponent(userId)}`;
// Результат: /api/users/%D0%98%D0%B2%D0%B0%D0%BD%20%D0%9F%D0%B5%D1%82%D1%80%D0%BE%D0%B2

Query-параметры (строка запроса)

После ? идут параметры вида key=value&another=data. Здесь нужно кодировать и ключи, и значения:

const query = 'iPhone 15';
const category = 'phones & tablets';
const url = `https://shop.com/search?q=${encodeURIComponent(query)}&cat=${encodeURIComponent(category)}`;
// Результат: https://shop.com/search?q=iPhone%2015&cat=phones%20%26%20tablets

Обратите внимание: пробел превратился в %20, а амперсанд & — в %26. Если не закодировать &, сервер решит, что это начало нового параметра.

В query-параметрах пробел иногда заменяют на + вместо %20 — это старое соглашение, работает в большинстве случаев, но %20 надёжнее.

Fragment (якорь)

После символа # идёт якорь — он обрабатывается браузером и не отправляется на сервер. Но если нужно закодировать что-то в нём, правила те же:

const anchor = 'раздел 1';
const url = `https://docs.com/page#${encodeURIComponent(anchor)}`;
// Результат: https://docs.com/page#%D1%80%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%201

Типичные ошибки при работе с API

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

Если применить encodeURIComponent() дважды, символ % сам закодируется в %25:

const text = 'hello world';
const wrong = encodeURIComponent(encodeURIComponent(text));
// Результат: hello%2520world (вместо hello%20world)

Сервер декодирует это в hello%20world вместо hello world. Ошибка возникает, когда кодирование делает и фронтенд, и библиотека для HTTP-запросов.

Кодирование всего URL целиком

Функция encodeURI() кодирует только часть символов, сохраняя структуру URL. Но для параметров её использовать нельзя:

const badUrl = encodeURI('https://api.com/search?q=hello world&sort=price');
// Результат: https://api.com/search?q=hello%20world&sort=price
// Пробел закодирован, но спецсимволы вроде & и = остались

Для параметров всегда используйте encodeURIComponent():

const params = new URLSearchParams({
  q: 'hello world',
  sort: 'price'
});
const goodUrl = `https://api.com/search?${params.toString()}`;
// Результат: https://api.com/search?q=hello+world&sort=price

Забыли закодировать заголовки

При отправке данных через заголовки (например, Authorization с токеном, содержащим спецсимволы) кодирование тоже может потребоваться:

const token = 'token+with/special=chars';
fetch('https://api.com/data', {
  headers: {
    'Authorization': `Bearer ${encodeURIComponent(token)}`
  }
});

Хотя в большинстве случаев токены состоят из безопасных символов, лучше перестраховаться.

Практические инструменты и проверка

Когда работаете с API, полезно проверять, правильно ли закодированы параметры. Это особенно важно при отладке сложных запросов с множеством параметров или при интеграции со сторонними сервисами.

Для быстрой кодировки текста используйте URL Encoder — вставьте строку и получите закодированный вариант. Если нужно декодировать параметр из логов или ответа сервера, поможет URL Decoder. Эти инструменты пригодятся, когда пишете документацию, тестируете эндпоинты или просто хотите понять, что скрывается за последовательностью %D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82.

В коде всегда используйте встроенные функции языка или библиотеки. В JavaScript это encodeURIComponent() и URLSearchParams, в Python — urllib.parse.quote(), в PHP — urlencode(). Не пытайтесь реализовать кодирование вручную через регулярные выражения — слишком много нюансов.

Инструменты по теме