1. Въведение
Най-просто казано, URL кодирането превежда специални символи от URL адреса в представяне, което се придържа към спецификацията и може да бъде правилно разбрано и интерпретирано.
В тази статия ще се съсредоточим върху това как да кодираме / декодираме URL или данните от формуляра, така че той да се придържа към спецификацията и да се предава правилно по мрежата.
2. Анализирайте URL адреса
Основен синтаксис на URI може да бъде обобщен като:
scheme:[//[user:[email protected]]host[:port]][/]path[?query][#fragment]
Първата стъпка в кодирането на URI е изследването на неговите части и след това кодирането само на съответните части.
Нека разгледаме пример за URI:
String testUrl = "//www.baeldung.com?key1=value+1&key2=value%40%21%242&key3=value%253";
Един от начините за анализ на URI е зареждането на представянето на String в клас java.net.URI :
@Test public void givenURL_whenAnalyze_thenCorrect() throws Exception { URI uri = new URI(testUrl); assertThat(uri.getScheme(), is("http")); assertThat(uri.getHost(), is("www.baeldung.com")); assertThat(uri.getRawQuery(), .is("key1=value+1&key2=value%40%21%242&key3=value%253")); }
Класът URI анализира URL адреса за представяне на низове и излага частите му чрез прост API - напр. GetXXX.
3. Кодирайте URL адреса
Когато кодирате URI, една от често срещаните клопки е кодирането на пълния URI. Обикновено трябва да кодираме само частта за заявка на URI.
Нека да кодираме данните, използвайки метода encode (data, encodingScheme) на класа URLEncoder :
private String encodeValue(String value) { return URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); } @Test public void givenRequestParam_whenUTF8Scheme_thenEncode() throws Exception { Map requestParams = new HashMap(); requestParams.put("key1", "value 1"); requestParams.put("key2", "[email protected]!$2"); requestParams.put("key3", "value%3"); String encodedURL = requestParams.keySet().stream() .map(key -> key + "=" + encodeValue(requestParams.get(key))) .collect(joining("&", "//www.baeldung.com?", "")); assertThat(testUrl, is(encodedURL));
Методът за кодиране приема два параметъра:
- data - низ за превод
- encodingScheme - име на кодирането на знака
Този метод на кодиране преобразува низа във формат application / x-www-form-urlencoded .
Схемата за кодиране ще преобразува специални символи в двуцифрено шестнадесетично представяне от 8 бита, които ще бъдат представени под формата на „ % xy “. Когато имаме работа с параметри на пътя или добавяне на динамични параметри, тогава ще кодираме данните и след това ще изпратим на сървъра.
Забележка: Препоръката на World Wide Web Consortium гласи, че трябва да се използва UTF-8 . Ако не го направите, това може да доведе до несъвместимости. (Справка: //docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html )
4. Декодирайте URL адреса
Нека сега декодираме предишния URL, използвайки метода за декодиране на URLDecoder :
private String decode(String value) { return URLDecoder.decode(value, StandardCharsets.UTF_8.toString()); } @Test public void givenRequestParam_whenUTF8Scheme_thenDecodeRequestParams() { URI uri = new URI(testUrl); String scheme = uri.getScheme(); String host = uri.getHost(); String query = uri.getRawQuery(); String decodedQuery = Arrays.stream(query.split("&")) .map(param -> param.split("=")[0] + "=" + decode(param.split("=")[1])) .collect(Collectors.joining("&")); assertEquals( "//www.baeldung.com?key1=value 1&[email protected]!$2&key3=value%3", scheme + "://" + host + "?" + decodedQuery); }
Двата важни бита тук са:
- анализирайте URL преди декодиране
- използвайте същата схема за кодиране за кодиране и декодиране
Ако трябваше да декодираме, отколкото да анализираме, частите на URL може да не бъдат анализирани правилно. Ако използвахме друга схема за кодиране за декодиране на данните, това би довело до данни за боклук.
5. Кодирайте сегмент от пътя
URLEncoder не може да се използва за кодиране на сегмент от пътя на URL адреса . Компонентът на пътя се отнася до йерархичната структура, която представлява път на директория, или служи за намиране на ресурси, разделени с „/“ .
Запазените символи в сегмента на пътя са различни от стойностите на параметъра на заявката. Например, знакът „+“ е валиден знак в сегмента на пътя и следователно не трябва да се кодира.
За да кодираме сегмента на пътя, вместо това използваме класа UriUtils от Spring Framework. Класът UriUtils предоставя методите encodePath и encodePathSegment за кодиране на пътя и съответно сегмента на пътя.
Нека разгледаме един пример:
private String encodePath(String path) { try { path = UriUtils.encodePath(path, "UTF-8"); } catch (UnsupportedEncodingException e) { LOGGER.error("Error encoding parameter {}", e.getMessage(), e); } return path; }
@Test public void givenPathSegment_thenEncodeDecode() throws UnsupportedEncodingException { String pathSegment = "/Path 1/Path+2"; String encodedPathSegment = encodePath(pathSegment); String decodedPathSegment = UriUtils.decode(encodedPathSegment, "UTF-8"); assertEquals("/Path%201/Path+2", encodedPathSegment); assertEquals("/Path 1/Path+2", decodedPathSegment); }
В горния кодов фрагмент можем да видим, че когато използвахме метода encodePathSegment , той връща кодираната стойност и + не се кодира, защото е стойностен знак в компонента на пътя.
Нека добавим променлива на пътя към нашия тестов URL:
String testUrl = "/path+1?key1=value+1&key2=value%40%21%242&key3=value%253";
и за да съберем и утвърдим правилно кодиран URL адрес, нека променим теста от раздел 2:
String path = "path+1"; String encodedURL = requestParams.keySet().stream() .map(k -> k + "=" + encodeValue(requestParams.get(k))) .collect(joining("&", "/" + encodePath(path) + "?", "")); assertThat(testUrl, CoreMatchers.is(encodedURL));
6. Заключение
В този урок видяхме как да кодираме и декодираме данните, така че да могат да бъдат прехвърлени и интерпретирани правилно. Докато статията се фокусира върху кодирането / декодирането на стойностите на параметрите на URI заявката, подходът се отнася и за параметрите на HTML формуляра.
Можете да намерите изходния код на GitHub.