Зачем кодировать URL
URL может содержать только ограниченный набор символов ASCII, и у нескольких из них есть своя работа. ? начинает строку запроса, & разделяет параметры, = отделяет имя от значения, # начинает фрагмент, а / разделяет сегменты пути. Если в поисковом запросе или имени файла встречается один из этих символов, браузер или сервер прочитает его как часть структуры, а не как данные.
Процентное кодирование решает это так: проблемный символ записывается как % и две шестнадцатеричные цифры. Пробел становится %20, & — %26, / — %2F. Символы вне ASCII сначала переводятся в байты UTF-8, и каждый байт кодируется отдельно, поэтому é превращается в %C3%A9, а одно эмодзи — в четыре группы %XX.
Когда это нужно:
- Собрать ссылку, где поисковый запрос, URL для редиректа или адрес почты передаётся параметром.
- Вложить один URL в другой, например значение
returnToилиredirect_uriв процессе входа. - Отлаживать вебхуки и ссылки аналитики, которые приходят нечитаемой «кашей» из
%. - Читать логи сервера, где запрошенные пути записаны в закодированном виде.
Кодирование компонента или URL целиком
Флажок Кодировать URL целиком (сохранить :/?&=) выбирает одно из двух разных правил, и ошибка в выборе — самая частая.
По умолчанию: кодирование компонента
Если флажок снят, кодируется всё, кроме букв, цифр и - _ . ! ~ * ' ( ). Это правильный выбор для одного значения, которое пойдёт после = в строке запроса или в один сегмент пути. Текст rock & roll/live превращается в rock%20%26%20roll%2Flive, который можно спокойно поставить в ?q=, не ломая список параметров.
URL целиком
Если флажок установлен, символы, задающие структуру URL, сохраняются: : / ? # & = + , ; @ $ и перечисленные выше. Пробелы, не-ASCII буквы и некоторые другие символы по-прежнему кодируются. Используйте этот режим, когда у вас есть полный адрес, который почти корректен, например https://example.com/files/annual report.pdf, и нужно исправить только пробел.
В режиме URL целиком нельзя отличить структурный & от того, что относится к значению. В https://shop.example/?q=salt & pepper символ & остаётся как есть, и сервер видит сломанный параметр. В таком случае закодируйте одно только значение в режиме компонента и вставьте его в URL.
Пробелы, плюсы и двойное кодирование
Для пробелов есть два соглашения. Кодирование путей и URL в целом использует %20; отправка HTML-форм (application/x-www-form-urlencoded) — +. Этот кодировщик всегда выдаёт %20, который любой сервер понимает в обоих местах.
Декодер перед раскодированием превращает + в пробел, потому что именно это означает плюс в строках запроса из форм. Побочный эффект: буквальный плюс, который никогда не кодировали, например C++ в пути, раскодируется как пробелы. Если в исходном тексте был настоящий знак плюс, его нужно было отправить как %2B — такая форма раскодируется правильно.
Вторая классическая ловушка — двойное кодирование. Сам знак % кодируется как %25, поэтому если прогнать уже закодированную строку через кодировщик ещё раз, %20 превратится в %2520. Если в неработающей ссылке видите %25 и две шестнадцатеричные цифры, раскодируйте её один раз и проверьте результат.
Если раскодировать не удаётся
«Некорректная закодированная строка» появляется, когда за % не следуют две шестнадцатеричные цифры или когда байты не образуют корректный UTF-8. Типичные причины:
- Обрезанная ссылка, оборванная посреди последовательности
%C3%A9. - Буквальный знак процента, как в
50% off, который не закодировали. - Текст, когда-то закодированный в устаревшей однобайтовой кодировке вроде Windows-1251 или Latin-1, где
é— это%E9, а не%C3%A9.
В первых двух случаях исправьте сломанную часть вручную. Для устаревших кодировок надёжного автоматического решения нет: один и тот же байт означает разные буквы в разных кодировках.
Родственные кодировки
Процентное кодирование — не то же самое, что Base64, который превращает произвольные байты в компактную строку, и не то же, что HTML-сущности вроде &, предназначенные для текста внутри HTML. Для читаемых адресов из заголовков «Генератор URL-slug» даёт более чистый результат, чем кодирование: My Trip to Kraków превращается в my-trip-to-krakow, а не в My%20Trip%20to%20Krak%C3%B3w.
Кодирование и раскодирование выполняются в браузере, так что токены или приватные параметры внутри URL никуда не отправляются.