Кодировок три, а не одна
encodeURIComponent, encodeURI и кодирование формы экранируют разные наборы
символов, и неверный выбор — обычная причина того, что адрес работает на тестах
и ломается на настоящих данных.
| Режим | Что экранирует | Для чего |
| --- | --- | --- |
| Компонент | & = ? / # +, пробел и всё не-ASCII | Одно значение параметра или сегмент пути |
| Весь URL | только не-ASCII, структура нетронута | Готовый адрес с диакритикой или кириллицей |
| Данные формы | как компонент, но пробел → + | Тело application/x-www-form-urlencoded |
Кодируйте части, потом собирайте
Надёжный порядок такой: закодировать каждое значение в режиме компонента, а
затем самому соединить их через ?, & и =. Кодировать уже собранный адрес
нельзя — к этому моменту разделители и данные выглядят одинаково.
Где это стреляет
Имя клиента с амперсандом, поисковый запрос с решёткой, имя файла с пробелом,
параметр редиректа, внутри которого лежит другой URL. Всё это обычные входные
данные, и все четыре ломают строку запроса, собранную руками и проверенную
только на test123.
Вопросы
Какой режим выбрать?+
«Компонент» — для одного значения параметра или сегмента пути: экранируются &, =, ? и /, чтобы их не приняли за структуру. «Весь URL» — когда есть готовый адрес с не-ASCII символами и структуру трогать не нужно. «Данные формы» — когда значение уходит в тело application/x-www-form-urlencoded, где пробел записывается как +, а не %20.
Почему при кодировании всего URL не экранировался амперсанд?+
Потому что в режиме всего URL амперсанд — это структура, он разделяет параметры. Если вы кодируете готовый адрес, внутри которого уже есть значение с &, вред уже нанесён: кодируйте каждое значение отдельно в режиме компонента, а потом собирайте URL.
Чем %20 отличается от +?+
Оба означают пробел, но в разных местах. %20 корректен в любой части URL. Соглашение с + действует только для тел форм и записанных в этом стиле строк запроса, а внутри пути + остаётся обычным плюсом. Их смешение — причина того, что поиск «a+b» превращается в поиск «a b».
Кириллица и emoji обрабатываются?+
Да. Текст сначала переводится в байты UTF-8, каждый байт кодируется процентами — так требует спецификация. Одна кириллическая буква даёт две экранирующие последовательности, emoji — четыре.