I'm running into a strange situation which I reproduced in https://github.com/lgueye/uri-parameters-behavior
Since we migrated to spring-boot 2 (spring framework 5) when requesting one of our backends in GET
method we ran into the following situation: all fields with a +
char were altered to (whitespace) char when they reached the backend
The following values are altered:
- +412386789 (phone number) into ** 412386789**
- 2019-03-22T17:18:39.621+02:00 (java8 ZonedDateTime) into 2019-03-22T17:18:39.621 02:00 (resulting in a org.springframework.validation.BindException
I've spent quite some time on stackoverflow (https://github.com/spring-projects/spring-framework/issues/14464#issuecomment-453397378) and github (https://github.com/spring-projects/spring-framework/issues/21577)
I've implemented both a mockMvc unit test and an integration test
The unit test behaves properly The integration test fails (like our production)
Can anyone point help me fix this issue ? My goal is obviously to make the integration test pass.
Thank you for your help.
Louis
The whole misalignment comes from the fact that there's a non-standard practice how to encode/decode space into
"+"
.Arguably space can(is being) encoded into
"+"
or"%20"
.For example Google does this to the search strings:
rfc1866, section-8.2.2
states that the query part of a GET request should be encoded in'application/x-www-form-urlencoded'
.On the other hand
rfc3986
states that spaces in URLs have to be encoded using"%20"
.This basically means there's a different standards to encode spaces, depending on where they are in the URI syntax components.
Based on these remarks, we can state that in GET http calls in URIs:
"?"
needs to be encoded to"%20"
"?"
in the query parameters needs to be encoded to"+"
"+"
signs needs to be encoded to"%2B"
in query parametersSpring implementation is following the rfc specifications, so that's why when you send "+412386789" in the query parameters, the
"+"
sign is interpreted as whitespace char and it gets to the backend as " 412386789".Looking at:
You will find that:
"foo#bar@quizz+foo-bazz//quir."
is encoded to"foo%23bar@quizz+foo-bazz//quir."
which conforms to the specification (rfc3986
).So if you want the
"+"
char in your query params to not be interpreted as space, you need to encode it to"%2B"
.The parameters you're sending to backend should look like:
In order to do that you can use
UrlEncoder
when passing the parameters to the map. Beware of UriComponentsBuilder double encoding your stuff!You can achieve correct URL with:
Note that passing "true" to the
build()
method turns off the encoding, so this means the scheme, host etc. from the URI parts won't be encoded properly byUriComponentsBuilder
.