Кодирование параметров запроса с помощью UriComponentsBuilder

Я изо всех сил пытаюсь понять поведение UriComponentsBuilder, Я хочу использовать его для кодирования URL-адреса в параметре запроса, однако он, по-видимому, только экранирует % символы, но не другие необходимые символы, такие как &,

Пример URL в параметре запроса, который вообще не кодируется:

UriComponentsBuilder.fromUri("http://example.com/endpoint")
                    .queryParam("query", "/path?foo=foo&bar=bar")
                    .build();

Выход: http://example.com/endpoint?query=/path?foo=foo&bar=bar

Это не правильно, потому что незашифрованный & причины bar=bar интерпретироваться как параметр запроса /endpoint вместо /path,

Однако, если я использую вход, который содержит % персонаж::

UriComponentsBuilder.fromUri("http://example.com/endpoint")
                    .queryParam("query", "/path?foo=%20bar")
                    .build();

Выход: http://example.com/endpoint?query=/path?foo=%2520bar

% персонаж сбежал.

Кажется непоследовательным, что UriComponentsBuilder будет автоматически избегать % символы, но не другие зарезервированные символы.

Какой правильный процесс для кодирования URL в параметр запроса с UriComponentsBuilder?

2 ответа

В вашем примере сборка UriComponents объект не закодирован или не нормализован. Чтобы убедиться, что применяется кодировка:

  1. Кодируй это сам, позвонив encode() метод (см. также normalize() метод):

    UriComponents u = UriComponentsBuilder.fromHttpUrl("http://example.com/endpoint")
      .queryParam("query", "/path?foo=foo&bar=bar")
      .build()
      .encode(); 
    // http://example.com/endpoint?query=/path?foo%3Dfoo%26bar%3Dbar
    
  2. использование build(true) метод, если параметры, используемые для построения UriComponents уже закодированы

    UriComponents u = UriComponentsBuilder.fromHttpUrl("http://example.com/endpoint")
      .queryParam("query", "/path?foo=foo&bar=bar")
      .build(true);
    // IllegalArgumentException: Invalid character '=' for QUERY_PARAM in "/path?foo=foo&bar=bar"
    

Под капотом HierarchicalUriComponents.encode(String) Метод выполняет фактическое кодирование. После нескольких внутренних звонков он вызывает HierarchicalUriComponents.encodeBytes(byte[], HierarchicalUriComponents.Type) где HierarchicalUriComponents.Type enum контролирует, какие символы разрешены в какой части URL. Эта проверка основана на RFC 3986. Короче говоря, у Spring есть своя логика кодирования для каждой части URL.

  1. Неверный синтаксис при использованииUriComponentsBuilder.fromUri() с String параметр вместо URI, Если вы хотите передать URL как String используйте это как:

      UriComponentsBuilder
      .fromUriString("http://example.com/endpoint")
      .queryParam("query", URLEncoder.encode("/path?foo=%20bar","UTF-8"))
      .build();
    
  2. & является допустимым символом URL, поэтому он не будет закодирован, но % не поэтому он декодируется %25,

Если вы хотите увидеть, как использовать то же самое с RestTemplate см.: RestTemplate.exchange () не кодирует "+"?

Другие вопросы по тегам