Выборочное кодирование URL в Java
На вход приходит строка вида
"http://127.0.0.1/servername/example.html?param1=value1¶m2=value2¶m3=Иванов Иван Иванович".
Сплитом отделяю параметры (по знаку вопроса), пропускаю через java.net.URLEncoder.encode. Соединяю обратно, получаю:
"http://127.0.0.1/servername/example.html?param1%3Dvalue1%26param2%3Dvalue2%26param3%3D%D0%98%D0%B2%D0%B0%D0%BD%D0%BE%D0%B2%20%D0%98%D0%B2%D0%B0%D0%BD%20%D0%98%D0%B2%D0%B0%D0%BD%D0%BE%D0%B2%D0%B8%D1%87"
На этой ссылке сервер ломается, потому что кириллицу и пробелы экранировать надо, а амперсанты, знаки равенства и прочее следует оставить как есть.
Если я первую ссылку запущу в хроме, то он её экранирует нормально: "http://127.0.0.1/servername/example.html?param1=value1¶m2=value2¶m3=%D0%98%D0%B2%D0%B0%D0%BD%D0%BE%D0%B2%20%D0%98%D0%B2%D0%B0%D0%BD%20%D0%98%D0%B2%D0%B0%D0%BD%D0%BE%D0%B2%D0%B8%D1%87"
Вопрос: почему браузер умеет, а Java нет? Как в джаве сделать такое же экранирование, не опускаясь до ручного хардкода замены каждой отдельной кириллической буквы?
Ответы (1 шт):
В поисках набрёл на эту тему и слегка допилил один из вариантов оттуда. Работает.
private static final String HEX = "0123456789ABCDEF";
public static String encodeURIComponent(String str) {
if (str == null) {
return null;
}
byte[] bytes = str.getBytes(Charset.forName("UTF8"));
StringBuilder builder = new StringBuilder(bytes.length);
for (byte c : bytes) {
if ((c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '~' || c == '_' || c == '-' || c == '.'
|| c == '=' || c == '&' || c == '%') {
builder.append((char) c);
} else {
builder.append('%')
.append(HEX.charAt(c >> 4 & 0xf))
.append(HEX.charAt(c & 0xf));
}
}
return builder.toString();
}