Почему Spring de-coding + (символ плюса) в приложении / json получает запросы?и что мне с этим делать? - PullRequest
0 голосов
/ 10 мая 2018

У меня есть приложение Spring, которое получает запрос типа http://localhost/foo?email=foo+bar@example.com.Это вызывает контроллер, который выглядит примерно так:

@RestController
@RequestMapping("/foo")
public class FooController extends Controller {
    @GetMapping
    public void foo(@RequestParam("email") String email) {
       System.out.println(email)
    }
}

К тому времени, когда я смогу получить доступ к email, он был преобразован в foo bar@example.com вместо исходного foo+bar@example.com.Согласно Когда кодировать пробел в плюс (+) или% 20? , это должно происходить только в запросах с контентом application/x-www-form-urlencoded.Мой запрос имеет тип контента application/json.Полные MIME-заголовки запроса выглядят так:

=== MimeHeaders ===
accept = application/json
content-type = application/json
user-agent = Dashman Configurator/0.0.0-dev
content-length = 0
host = localhost:8080
connection = keep-alive

Почему Spring тогда декодирует плюс как пробел?И если это так, как оно должно работать, почему он не кодирует плюсы как %2B при выполнении запросов ?

Я нашел этот отчет об ошибке: https://jira.spring.io/browse/SPR-6291, что может означать, что это исправлено в версии 3.0.5, и я использую Spring> 5.0.0.Вполне возможно, что я могу неправильно истолковать что-то об отчете об ошибке.

Я также нашел это обсуждение обработки RestTemplate этих значений: https://jira.spring.io/browse/SPR-5516 (мой клиент использует RestTemplate).

Итак, мои вопросы: почему Spring делает это?Как я могу отключить это?Стоит ли его отключать или кодировать плюсы на клиенте, даже если запросы json?

Просто чтобы уточнить, я нигде не использую ни HTML, ни JavaScript.Есть Spring Rest Controller, и клиент имеет Spring 10 * с UriTemplate или UriComponentsBuilder, ни один из которых не кодирует знак плюс, как Spring декодирует его.

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

Если у вас есть этот запрос:

http://localhost/foo?email=foo+bar@example.com

, то оригинал равен foo bar@example.com.Если вы говорите, что оригинал должен быть foo+bar@example.com, тогда запрос должен быть :

http://localhost/foo?email=foo%2Bbar@example.com

Таким образом, Spring работает как положено.Возможно, на клиенте вы должны проверить, правильно ли закодирован URI.Кодирование URL на стороне клиента отвечает за создание правильного HTTP-запроса.

См. encodeURI () , если вы генерируете запрос в JavaScript, или uriToString () , если высгенерируйте запрос в Spring.

Создайте строку запроса (часть после ?), без какой-либо кодировки, с незакодированными значениями, такими как foo+bar@email.com, и только в конце, прежде чем фактически использовать ее в GET, закодируйте все это с тем, что доступно на клиентской платформе.Если вы хотите использовать POST, вам следует закодировать его в соответствии с выбранным вами типом MIME.

0 голосов
/ 22 мая 2018

SPR-6291 исправил эту проблему в v3.0.5, но это остается нерешенной в некоторых других случаях, таких как SPR-11047 до сих пор не решена. В то время как приоритет SPR-6291 был Major , приоритет SPR-11047 Minor .

SPR-11047

Я столкнулся с этой проблемой, когда работал в прошлом году над REST API в старой Spring. Есть несколько способов получить данные в Spring controller. Таким образом, два из них через @RequestParam или @PathVariable аннотацию

Как уже упоминалось, я думаю, что внутренняя проблема этой пружины не относится конкретно к URL кодировке , потому что я отправлял данные по запросу POST, но это в некоторой степени проблема кодирования. Но я также согласен с другими, так как теперь это остается проблематичным только в URL.

Итак, есть два решения Я знаю:

  1. Вы можете использовать @PathVariable вместо @RequestParam, поскольку с SPR-6291 эта проблема со знаком плюс исправлена ​​ в @PathVariable и остается открытой для @RequestParam как SPR-11047

  2. Моя версия Spring даже не принимала знак плюс через аннотацию @PathVariable, поэтому я преодолеваю проблему (я не помню ее шаг за шагом, но она даст ты намекнишь).

В вашем случае вы можете получить поля через JS и escape знак плюс перед отправкой запроса. Примерно так:

var email = document.getElementById("emailField").value;
email = email.replace('+', '%2B');
0 голосов
/ 20 мая 2018

Оригинальный ответ

Вы смешиваете 2 вещи, а + в теле запроса будет означать пробел, если заголовок имеет application/x-www-form-urlencoded.Тело или содержание запроса будет зависеть от заголовков, но запрос может иметь только url, а не headers и нет body.

Таким образом, кодировка URI не может контролироваться никакими заголовками как таковыми

См. Раздел URL Encoding в https://en.wikipedia.org/wiki/Query_string

Некоторые символы не могут быть частьюURL (например, пробел) и некоторые другие символы имеют специальное значение в URL: например, символ # может использоваться для дополнительного указания подраздела (или фрагмента) документа.В формах HTML символ = используется для отделения имени от значения.Общий синтаксис URI использует кодировку URL для решения этой проблемы, в то время как HTML-формы делают некоторые дополнительные замены, а не применяют процентное кодирование для всех таких символов.SPACE кодируется как '+' или "% 20". [10]

HTML 5 определяет следующее преобразование для отправки HTML-форм с помощью метода "get" на веб-сервер. 1 Ниже приводится краткое описание алгоритма:

Символы, которые не могут быть преобразованы в правильную кодировку, заменяются цифровыми ссылками на символы HTML [11] ПРОБЕЛ кодируется буквами '+' или '% 20' (A–Z и a – z), цифры (0–9) и символы «*», «-», «.»и '_' оставлены как есть. Все остальные символы закодированы как шестнадцатеричное представление% HH с любыми не-ASCII символами, сначала закодированными как UTF-8 (или другое заданное кодирование). Октет, соответствующий тильде ("~"), разрешенв строках запроса по RFC3986, но в HTML-формах требуется кодирование в процентах в «% 7E».

Кодировка SPACE в виде «+» и выбор символов «как есть» отличает эту кодировку от RFC3986.

И вы можете увидеть то же поведение на google.com, а также снизу скриншоты

+ translated to space

%2B translated to +

Также вы можете увидеть такое же поведение и в других платформах.Ниже приведен пример Python Flask

Flask Demo

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

Edit-1: 22 мая

После отладки кажется, что декодирование даже не происходит в Spring.Я происходил в package org.apache.tomcat.util.buf; и UDecode классе

/**
 * URLDecode, will modify the source.
 * @param mb The URL encoded bytes
 * @param query <code>true</code> if this is a query string
 * @throws IOException Invalid %xx URL encoding
 */
public void convert( ByteChunk mb, boolean query )
    throws IOException
{
    int start=mb.getOffset();

И ниже, где фактически происходит конвертация

    if( buff[ j ] == '+' && query) {
        buff[idx]= (byte)' ' ;
    } else if( buff[ j ] != '%' ) {

Это означает, что это встроенный сервер Tomcat, который делаетэтот перевод и весна даже не участвуют в этом.Нет конфигурации для изменения этого поведения, как видно из кода класса.Таким образом, вы должны жить с этим

...