'URL encoding using the new Spring UriComponentsBuilder
I'm attempting to use spring's UriComponentsBuilder to generate some urls for oauth interaction. The query parameters include such entities as callback urls and parameter values with spaces in them.
Attempting to use UriComponentBuilder (because UriUtils is now deprecated)
UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(oauthURL);
urlBuilder.queryParam("client_id", clientId);
urlBuilder.queryParam("redirect_uri", redirectURI);
urlBuilder.queryParam("scope", "test1 test2");
String url = urlBuilder.build(false).encode().toUriString();
Unfortunately, while the space in the scope parameter is successfully replaced with '+', the redirect_uri parameter is not at all url encoded.
E.g,
redirect_uri=https://oauth2-login-demo.appspot.com/code
should have ended up
redirect_uri=https%3A%2F%2Foauth2-login-demo.appspot.com%2Fcode
but was untouched. Diving into the code, specifically org.springframework.web.util.HierarchicalUriComponents.Type.QUERY_PARAM.isAllowed(c) :
if ('=' == c || '+' == c || '&' == c) {
return false;
}
else {
return isPchar(c) || '/' == c || '?' == c;
}
clearly allows ':' and '/' characters, which by gum, it shouldn't. It must be doing some other type of encoding, though for the life of me, I can't imagine what. Am I barking up the wrong tree(s) here?
Thanks
Solution 1:[1]
from what I understand, UriComponentsBuilder doesn't encode the query parameters automatically, just the original HttpUrl it's instantiated with. In other words, you still have to explicitly encode:
String redirectURI= "https://oauth2-login-demo.appspot.com/code";
urlBuilder.queryParam("redirect_uri", URLEncoder.encode(redirectURI,"UTF-8" ));
Solution 2:[2]
Try to scan the UriComponentsBuilder doc, there is method named build(boolean encoded)
Sample code 1:
UriComponents uriComponents = UriComponentsBuilder.fromPath("/path1/path2").build(true);
Here is my sample code 2:
UriComponents uriComponents = UriComponentsBuilder.newInstance()
.scheme("https")
.host("my.host")
.path("/path1/path2").query(parameters).build(true);
URI uri= uriComponents.toUri();
ResponseEntity<MyEntityResponse> responseEntity = restTemplate.exchange(uri,
HttpMethod.GET, entity, typeRef);
Solution 3:[3]
I tried all the solutions above until I got it working.
In my example, I was trying to encode the ZonedDateTime format 2022-01-21T10:17:10.228+06:00. The plus sign was a problem.
What solved my issue was encoding the value manually + using URI instead of the string value (both were very important).
Before:
restTemplate.exchange(
UriComponentsBuilder
.queryParam("fromDateTime", "2022-01-21T10:17:10.228+06:00")
.build()
.toUriString(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<MyDto>>() {}
);
After:
restTemplate.exchange(
UriComponentsBuilder
.queryParam("fromDateTime", URLEncoder.encode("2022-01-21T10:17:10.228+06:00", StandardCharsets.UTF_8))
.build(true)
.toUri(),
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<MyDto>>() {}
);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Black |
| Solution 2 | Andoy Abarquez |
| Solution 3 | Tomas Lukac |
