Punycode для параметра запроса Unicode
Я пытаюсь закодировать некоторые URL-адреса Unicode с Punycode. Эти URL имеют параметр запроса, который содержит символы не ASCII, например:
https://en.wiktionary.org/w/index.php?title=Clœlia&printable=yes
Проблема в том, что, когда я пытаюсь сделать это на Java, полученный URL-адрес неверен:
String link = "https://en.wiktionary.org/w/index.php?title=Clœlia&printable=yes";
link = IDN.toASCII(link);
// -> link = http://en.wiktionary.org/w/index.xn--php?title=cllia&printable=yes-hgf
Если я сделаю это таким образом, результирующая строка будет другой (я не знаю почему), но также неверна:
String link = "http://en.wiktionary.org/w/index.php?title=" + IDN.toASCII("Clœlia") + "&printable=yes";
// -> link = http://en.wiktionary.org/w/index.php?title=xn--cllia-ibb&printable=yes
Если я скопирую адрес из Chrome и вставлю его сюда, я получу этот URL, который мне нужен:
https://en.wiktionary.org/w/index.php?title=Cl%C5%93lia&printable=yes
Что я тут не так сделал?
1 ответ
То, что вы сделали неправильно, это использовать punycode. Punycode используется только для доменных имен, включая часть имени домена в URL.
Другие части URL, включая часть параметров запроса, используют Percent Encoding, также известную как кодировка URL или URI, и это то, что делает Chrome; это кодирует не-ASCII символы Unicode в UTF-8, а затем все октеты, которые не входят в ограниченное подмножество ASCII, используя знак процента (%) и две шестнадцатеричные цифры; октеты 80-FF, используемые UTF-8 для не-ASCII, всегда кодируются%. Чтобы быть точным, часть параметра запроса обычно и другие части иногда используют небольшой вариант, определенный для представления формы HTML как application/x-www-form-urlencoded
; это кодирует пробел как знак плюса "+" вместо%20, что однозначно, потому что "+" уже находится в небезопасном наборе, поэтому кодируется как%2B.
В Java использовать java.net.URLEncoder.encode
а также java.net.URLDecoder.decode
за это; для получения достоверных результатов используйте более новые формы 2-arg с кодировкой "UTF-8".