Что такое URL-кодирование?
URL-кодирование (percent-encoding) — механизм, определённый RFC 3986 для передачи данных внутри URL. Символы, имеющие зарезервированное значение в URL (например, ? / # & =), или символы вне диапазона ASCII перезаписываются в виде одного или более триплетов %XX, где XX — шестнадцатеричное значение байта. Декодеры выполняют обратное преобразование побайтово.
Percent-encoding — это транспортный формат, а не механизм безопасности. Любой, кто получает закодированную строку, может тривиально её декодировать. Не путайте кодирование с шифрованием или хешированием.
Как выбрать режим
Этот инструмент предоставляет три режима кодирования, с которыми каждый разработчик рано или поздно сталкивается. Выбранный режим определяет, какие символы будут закодированы.
Режим Component (encodeURIComponent). Используйте, когда кодируете отдельное значение, которое будет встроено в URL: значение query-параметра, сегмент пути, фрагмент. Он кодирует все URL-зарезервированные символы, так что результат безопасен в любом месте.
Режим Whole URL (encodeURI). Используйте, когда у вас уже есть собранный URL и нужно экранировать только небезопасные символы (пробелы, не-ASCII). Структурные символы : / ? # & = + остаются нетронутыми, чтобы URL оставался разбираемым.
Режим Form (application/x-www-form-urlencoded). Используйте, когда формируете тело HTTP-запроса с Content-Type: application/x-www-form-urlencoded. Пробел превращается в +, переводы строк нормализуются в CRLF (%0D%0A), а набор символов соответствует тому, что браузер отправляет при отправке HTML-формы.
Зарезервированные символы
| Символ | Component | Whole URL | Form |
|---|---|---|---|
| (space) | %20 | %20 | + |
| ! | ! | ! | %21 |
| " | %22 | %22 | %22 |
| # | %23 | # | %23 |
| $ | %24 | $ | %24 |
| % | %25 | %25 | %25 |
| & | %26 | & | %26 |
| ' | ' | ' | %27 |
| ( | ( | ( | %28 |
| ) | ) | ) | %29 |
| * | * | * | * |
| + | %2B | + | %2B |
| , | %2C | , | %2C |
| / | %2F | / | %2F |
| : | %3A | : | %3A |
| ; | %3B | ; | %3B |
| = | %3D | = | %3D |
| ? | %3F | ? | %3F |
| @ | %40 | @ | %40 |
| [ | %5B | %5B | %5B |
| ] | %5D | %5D | %5D |
| ~ | ~ | ~ | %7E |
| %0A | %0A | %0D%0A | |
| 中 | %E4%B8%AD | %E4%B8%AD | %E4%B8%AD |
Component кодирует всё, кроме незарезервированного набора A–Z a–z 0–9 - _ . ! ~ * ' ( ). Whole URL дополнительно сохраняет структурный набор ; , / ? : @ & = + $ # !. Form кодирует тот же набор, что Component, плюс ! ' ( ) ~ (но не *), превращает пробел в + вместо %20 и нормализует \n / \r / \r\n в \r\n (кодируется как %0D%0A) — соответствуя тому, что браузер отправляет для application/x-www-form-urlencoded.
Типичные сценарии
Программное формирование query-строк: когда вы собираете URL вида /search?q=[value] вручную, прогоните значение через режим Component, чтобы символы вроде & или = внутри значения не ломали URL.
Встраивание URL в другой URL: когда вы передаёте один URL как параметр другого (например, OAuth redirect URL), внутренний URL нужно кодировать через Component, а не Whole URL, чтобы / : ? & внутри внутреннего URL не воспринимались как часть внешнего URL.
Отправка данных формы через fetch: когда вы POST-ите тело с Content-Type: application/x-www-form-urlencoded, тело должно быть закодировано с семантикой Form. Этот режим выдаёт байт-совместимый результат с тем, что отправляет браузер.
Ограничения
URL-кодирование не является шифрованием. Любой может декодировать результат одним вызовом функции. Никогда не используйте кодирование для скрытия секретов.
Выбор режима важен. Прогон целого URL через Component ломает его (каждый / становится %2F). Прогон значения query-параметра через Whole URL может оставить опасные символы (& в значении всё ещё выглядит как разделитель параметров). Если сомневаетесь — выбирайте Component.