О кодировании и декодировании URL
Что такое URL-кодирование и почему текст превращается в %E4%B8%AD
Стандарт URL (RFC 3986) разрешает только латинские буквы, цифры и горстку символов. Кириллица, иероглифы, пробелы, кавычки в этот список не входят. Чтобы поместить их в ссылку, их сначала переводят в байты какой-нибудь кодировкой, а затем каждый байт записывают знаком процента и двумя шестнадцатеричными цифрами — это и есть процентное кодирование, оно же URL-кодирование. Символ 中 занимает в UTF-8 три байта, E4 B8 AD, которые записываются как %E4%B8%AD. Так что вереница %E4%B8... — это не крякозябры и не шифр, а просто другая запись того же текста; идущие по три %XX подряд почти наверняка означают иероглифы в UTF-8, а кириллица занимает по два байта и выглядит как %D0../%D1..
encodeURIComponent или encodeURI — что выбрать
Это то, в чём при написании кода ошибаются чаще всего. encodeURIComponent кодирует и : / ? # & = — структурные символы, и потому годится для одного значения параметра; encodeURI их оставляет и подходит для уже собранной целиком ссылки. Ошибка здесь даёт вполне осязаемый результат: передайте весь URL в encodeURIComponent, https:// превратится в https%3A%2F%2F, и ссылка попросту сломается. Наоборот, взяв encodeURI для значения параметра, в котором и так есть & (скажем, поисковый запрос «A&B»), вы получите вот что: этот & останется нетронутым, сервер примет его за разделитель, и один параметр приедет к нему как два. Кодировщик выше умеет и то и другое; по умолчанию выбран режим для значения параметра.
URL-кодирование — не шифрование
URL-кодирование, как и Base64, — это кодирование, а не шифрование: правила полностью открыты, ключа нет, и любой, у кого есть строка, разворачивает её в одно действие — эта страница ровно этим и занимается. Смысл его в том, чтобы спецсимволы благополучно прошли по каналу под названием URL, и никакой секретности он не даёт. Поэтому номер заказа, телефон или внутренний идентификатор, пропущенный через URL-кодирование перед вставкой в ссылку, не защищён ничем: и в адресной строке, и в логах сервера, и в заголовке Referer лежит открытый текст. Если нужна необратимость, посмотрите соседний инструмент: SHA-256. А чувствительные параметры передавайте методом POST поверх HTTPS. И, к слову, «расшифровки URL» попросту не существует — правильное слово «декодирование».
Три ловушки: плюс, %20 и крякозябры
У пробела две записи. Отправка форм использует application/x-www-form-urlencoded и кодирует пробел как +, а в путях и современных API обычно берут %20. Загвоздка в том, что в JavaScript decodeURIComponent не понимает + вовсе и оставляет плюс как есть — отсюда и переключатель выше, по умолчанию читающий его как пробел. И наоборот: если плюс в содержимом настоящий (скажем, 1+1), при кодировании он станет %2B, и это правильно.
Вторая ловушка — кодировка. Сегодня по умолчанию везде UTF-8, но немало старых сайтов и систем работают на GBK, где 中 — это два байта, %D6%D0. Раскодируйте содержимое в GBK как UTF-8 — и получите вопросительные знаки или квадратики. На стороне декодирования эта страница позволяет переключиться на GBK; сторона кодирования работает только с UTF-8, потому что больше браузер сам ничего и не умеет.
Соответствие имён функций по языкам. В PHP urlencode превращает пробел в +, rawurlencode даёт %20; обратные им — urldecode / rawurldecode; в Java URLEncoder.encode(s, "UTF-8") работает по правилам форм, а значит, тоже +; Python использует urllib.parse.quote / unquote, причём только quote_plus выдаёт +; а в JavaScript есть один encodeURIComponent / decodeURIComponent, и он всегда даёт %20. Когда фронтенд с бэкендом не сходятся, дело почти всегда в этом плюсе.