2017-01-06 4 views
4

У меня странная проблема с urlencoding знаком плюса + в качестве параметра запроса для запроса к API. В документации к API указано:Проблема с кодировкой странного url

Дата должна быть в формате W3C, например. '2016-10-24T13: 33: 23 + 02: 00'.

До сих пор так хорошо, поэтому я использую этот код (minimalized) для генерации URL, используя UriComponentBuilder весны:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX"); 
ZonedDateTime dateTime = ZonedDateTime.now().minusDays(1); 
String formated = dateTime.format(formatter); 

UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUrl); 
uriComponentsBuilder.queryParam("update", formated); 
uriComponentsBuilder.build(); 
String url = uriComponentsBuilder.toUriString(); 

неперекодированный запрос будет выглядеть следующим образом:

https://example.com?update=2017-01-05T12:40:44+01 

кодированные результаты: строка в

https://example.com?update=2017-01-05T12:40:44%2B01 

который (ИМХО) правильно закодированный запрос Строка. См. %2B, заменяя + на +01 в конце строки запроса.

Теперь, когда я отправляю запрос против API с использованием кодированного URL-адреса, я получаю сообщение об ошибке, когда запрос не может быть обработан.

Однако, если я заменю %2B с + перед отправкой запроса, он работает:

url.replaceAll("%2B", "+"); 

Из моего понимания, + знака является заменой для whitespace. Таким образом, URL, что сервер действительно видит после декодирования должен быть

https://example.com?update=2017-01-05T12:40:44 01 
  • Правильно ли я с этим предположением?

  • Есть ли что-нибудь, что я могу сделать, кроме как связаться с владельцем API, чтобы заставить его работать с использованием правильно закодированного запроса, кроме странных нестандартных замен строк?

UPDATE:

В соответствии со спецификацией RFC 3986 (раздел 3.4), то + знака в парах запроса не должен быть закодирован.

3.4. Компонент запроса

Запрос содержит не-иерархические данные, которые, наряду с данных в компоненте пути (раздел 3.3), служит для идентификации
ресурса в рамках схемы URI, и присвоения имени органа
(если таковые имеются). Компонент запроса указывается первым вопросом
символом метки («?») И заканчивается знаком числа («#»)
или к концу URI.

Berners-Lee, et al. Стандарты Track [Page 23] RFC 3986 URI Generic Syntax
января 2005

query  = *(pchar/"/"/"?") 

Символы слэш ("/") и знак вопроса ("?") Могут представлять данные внутри компонента запроса. Учтите, что некоторые старые, ошибочные реализации не может обрабатывать такие данные правильно, когда он используется в качестве , основание URI для относительных ссылок (раздел 5.1), по-видимому
, потому что они не могут отличить данные запроса по данным пути, когда
ищет иерархическое сепараторы. Тем не менее, в качестве компонентов запроса
часто используется для передачи идентификационной информации в форме
«ключ = значение» пара и один часто используемого значения является ссылкой на
другого URI, иногда лучше, для удобства использования, чтобы избежать percent-
кодировка этих символов.

Согласно this answer on stackoverflow, пружина UriComponentBuilder использует эту спецификацию, но, похоже, на самом деле это не так. Итак, новый вопрос: как заставить UriComponentBuilder следовать спецификациям?

+0

Обратитесь к таблице, представленной @Simon Tewsi http://stackoverflow.com/questions/575440/url-encoding- используя-c-sharp – Prabu

+2

@Prabu, Ваша ссылка не отвечает на вопрос. OP хочет знать, почему служба принимает только знак некодированного плюса, а не как его кодировать или нет, или какие утилиты C# использовать. Быстрая проверка правил кодирования указывает, что обстоятельства, при которых зарезервированные символы кодируются или должны быть закодированы, слегка изменились, но я не видел ничего, чтобы предположить, что знак плюса, используемый как часть форматированной строки даты, не должен быть закодирован. – arcy

+0

Это то, что я тоже думаю @arcy – Michael

ответ

0

Так что похоже UriComponentBuilder весны кодирует весь URL, установив флаг кодирования в false в методе build() не имеет никакого эффекта, так как метод toUriString() ВСЕГДА кодирует URL, так как она вызывает encode() явно после build():

/** 
* Build a URI String. This is a shortcut method which combines calls 
* to {@link #build()}, then {@link UriComponents#encode()} and finally 
* {@link UriComponents#toUriString()}. 
* @since 4.1 
* @see UriComponents#toUriString() 
*/ 
public String toUriString() { 
    return build(false).encode().toUriString(); 
} 

Решение для меня (на данный момент) кодирует то, что действительно нужно кодировать вручную. Другим решением может быть (может потребовать кодирующая тоже) получение URI и работать с этим далее

String url = uriComponentsBuilder.build().toUri().toString(); // returns the unencoded url as a string 
0

Кодирование 2017-01-05T12:40:44+01

дает 2017-01-05T12%3A40%3A44%2B01

вместо 2017-01-05T12:40:44%2B01, как вы предложили.

Возможно, поэтому сервер не может обрабатывать ваш запрос, это полукодированная дата.

+1

Нет, это не проблема – Michael