Spring RestTemplate getForObject URL not working for Apple iTunes - java

I created the following simple test to query iTunes:
#Test
fun loadArtist()
{
val restTemplate = RestTemplate()
val builder = UriComponentsBuilder.fromHttpUrl("https://itunes.apple.com/search")
builder.queryParam("term", "howling wolf")
builder.queryParam("entity", "allArtist")
builder.queryParam("limit", 1)
println("\n\nURL ${builder.toUriString()}")
val result = restTemplate.getForObject(builder.toUriString(), String::class.java);
println("Got artist: $result")
}
And the output was unexpected:
URL https://itunes.apple.com/search?term=howling%20wolf&entity=allArtist&limit=1
Got artist:
{
"resultCount":0,
"results": []
}
Pasting the generated URL into a browser does give expected results - artist returned.
https://itunes.apple.com/search?term=howling%20wolf&entity=allArtist&limit=1
Also, hard-coding the query works:
val result = restTemplate.getForObject("https://itunes.apple.com/search?term=howling%20wolf&entity=allArtist&limit=1", String::class.java);
. . the problem only seems to occur for term queries that include spaces.
What went wrong? Other than assemble the URL by hand, how to fix?

Seems like a case of double encoding the whitespace. From the RestTemplate Javadoc:
For each HTTP method there are three variants: two accept a URI
template string and URI variables (array or map) while a third accepts
a URI. Note that for URI templates it is assumed encoding is
necessary, e.g. restTemplate.getForObject("http://example.com/hotel
list") becomes "http://example.com/hotel%20list". This also means if
the URI template or URI variables are already encoded, double encoding
will occur, e.g. http://example.com/hotel%20list becomes
http://example.com/hotel%2520list). To avoid that use a URI method
variant to provide (or re-use) a previously encoded URI. To prepare
such an URI with full control over encoding, consider using
UriComponentsBuilder.
So it looks like getForObject will actually query for https://itunes.apple.com/search?term=howling%2520wolf&entity=allArtist&limit=1 and thus result in an empty result. You can always just replace whitespaces with a "+" in your term or try to make one of those classes skip the encoding process.

Related

How can i use % with RestTemplate

I am trying to make a HTTP request to a API with a route like this:
https://example.test/{ID}/get
The problem is, the ID starts with %, something like "%123123123", after the "excute" method, locate in RestTemplate class, this ID's becomes %25123123123, % changes into %25.
More specific, in this line of the method:
URI expanded = getUriTemplateHandler().expand(url, uriVariables);
Here my uriVariables is just a empty Object, and when i manually change the value of expanded variable removing "25", the request works just fine.
Anyone knows how to fix it ?
After Spring 5, the DefaultUriBuilderFactory, used by RestTemplate, defaults is EncodingMode.URI_COMPONENT, as described below:
Expand URI variables first, and then encode the resulting URI component values, replacing only non-ASCII and illegal (within a given URI component type) characters, but not characters with reserved meaning.
If you want your URI to be unencoded like I do, just create a new DefaultUriBuilderFactory with EncodingMode.NONE and add it to your RestTemplate:
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory();
uriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
You can check here for other EncondingModes.

How to build a URI using URIbuilder without encoding hash

I have a URI like this:
java.net.URI location = UriBuilder.fromPath("../#/Login").queryParam("token", token).build();
and I am sending it as response: return Response.seeOther(location).build()
However, in the above URI, # is getting encoded to %23/. How do I create a URI with out encoding the hash #. According to official document, a fragment() method must be used to keep unencoded.
URI templates are allowed in most components of a URI but their value
is restricted to a particular component. E.g.
UriBuilder.fromPath("{arg1}").build("foo#bar"); would result in
encoding of the '#' such that the resulting URI is "foo%23bar". To
create a URI "foo#bar" use
UriBuilder.fromPath("{arg1}").fragment("{arg2}").build("foo", "bar") instead.
Looking at the example from docs, I am not sure how to apply it in my case.
The final URI should look like this:
http://localhost:7070/RTH_Sample14/#Login?token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvcnRoLmNvbSIsInN1YiI6IlJUSCIsInJvbGUiOiJVU0VSIiwiZXhwIjoxNDU2Mzk4MTk1LCJlbWFpbCI6Imtpcml0aS5rOTk5QGdtYWlsLmNvbSJ9.H3d-8sy1N-VwP5VvFl1q3nhltA-htPI4ilKXuuLhprxMfIx2AmZZqfVRUPR_tTovDEbD8Gd1alIXQBA-qxPBcxR9VHLsGmTIWUAbxbyrtHMzlU51nzuhb7-jXQUVIcL3OLu9Gcssr2oRq9jTHWV2YO7eRfPmHHmxzdERtgtp348
To construct the URI with fragment use
UriBuilder.fromPath("http://localhost:7070/RTH_Sample14/").fragment("Login").build()
This results in the URI string
http://localhost:7070/RTH_Sample14/#Login
But if you also add query parameters
UriBuilder.fromPath("http://localhost:7070/RTH_Sample14/").fragment("Login")
.queryParam("token", "t").build()
then the UriBuilder always inserts the query params before the fragment:
http://localhost:7070/RTH_Sample14/?token=t#Login
which simply complies to the URL syntax.
Instead of all the hassle of redirecting without encoding the hash value. I changed my code into the following:
java.net.URI location = new java.net.URI("../#/Login?token=" + token);
So the query param above is token appended to URI location. In front-end I am using angular's location.search().token to get capture the query param.
This worked for me. Looking for better answers though. Thanks

Need to replace spaces inside string with percentual symbol Java

I need to replace the spaces inside a string with the % symbol but I'm having some issues, what I tried is:
imageUrl = imageUrl.replace(' ', "%20");
But It gives me an error in the replace function.
Then:
imageUrl = imageUrl.replace(' ', "%%20");
But It still gives me an error in the replace function.
The I tried with the unicode symbol:
imageUrl = imageUrl.replace(' ', (char) U+0025 + "20");
But it still gives error.
Is there an easy way to do it?
String.replace(String, String) is the method you want.
replace
imageUrl.replace(' ', "%");
with
imageUrl.replace(" ", "%");
System.out.println("This is working".replace(" ", "%"));
I suggest you to use a URL Encoder for Encoding Strings in java.
String searchQuery = "list of banks in the world";
String url = "http://mypage.com/pages?q=" + URLEncoder.encode(searchQuery, "UTF-8");
I've ran into issues like this in the past with certain frameworks. I don't have enough of your code to know for sure, but what might be happening is whatever http framework you are using, in my case it was spring, is encoding the URL again. I spent a few days trying to solve a similar problem where I thought that string replace and the URI.builder() was broken. What ended up being the problem was that my http framework had taken my encoded url, and encoded it again. that means that any place it saw a "%20", it would see the '%' charictor and switch it out for '%' http code, "%25", resulting in. "%2520". The request would then fail because %2520 didn't translate into the space my server was expecting. While the issue apeared to be one of my encoding not working, it was really an issue of encoding too many times. I have an example from some working code in one of my projects below
//the Url of the server
String fullUrl = "http://myapiserver.com/path/";
//The parameter to append. contains a space that will need to be encoded
String param 1 = "parameter 1"
//Use Uri.Builder to append parameter
Uri.Builder uriBuilder = Uri.parse(fullUrl).buildUpon();
uriBuilder.appendQueryParameter("parameter1",param1);
/* Below is where it is important to understand how your
http framework handles unencoded url. In my case, which is Spring
framework, the urls are encoded when performing requests.
The result is that a url that is already encoded will be
encoded twice. For instance, if you're url is
"http://myapiserver.com/path?parameter1=param 1"
and it needs to be read by the server as
"http://myapiserver.com/path?parameter1=param%201"
it makes sense to encode the url using URI.builder().append, or any valid
solutions listed in other posts. However, If the framework is already
encoding your url, then it is likely to run into the issue where you
accidently encode the url twice: Once when you are preparing the URL to be
sent, and once again when you are sending the message through the framework.
this results in sending a url that looks like
"http://myapiserver.com/path?parameter1=param%25201"
where the '%' in "%20" was replaced with "%25", http's representation of '%'
when what you wanted was
"http://myapiserver.com/path?parameter1=param%201"
this can be a difficult bug to squash because you can copy the url in the
debugger prior to it being sent and paste it into a tool like fiddler and
have the fiddler request work but the program request fail.
since my http framework was already encoding the urls, I had to unencode the
urls after appending the parameters so they would only be encoded once.
I'm not saying it's the most gracefull solution, but the code works.
*/
String finalUrl = uriBuilder.build().toString().replace("%2F","/")
.replace("%3A", ":").replace("%20", " ");
//Call the server and ask for the menu. the Menu is saved to a string
//rest.GET() uses spring framework. The url is encoded again as
part of the framework.
menuStringFromIoms = rest.GET(finalUrl);
There is likely a more graceful way to keep a url from encoding twice. I hope this example helps point you on the right direction or eliminate a possability. Good luck.
Try this:
imageUrl = imageUrl.replaceAll(" ", "%20");
Replace spaces is not enought, try this
url = java.net.URLEncoder.encode(url, "UTF-8");

URL percent encoding query param Bing API Java

I'm trying to URL percent encode my query param value while using URIBuilder to make an HTTP request to Bing API.
The url looks like
"https://api.datamarket.azure.com/Data.ashx/Bing/SearchWeb/v1/Web?$format=json&Query="
Where the Query String must be like
%27Test%20query%27
Using URLEncoder.encode(string, code), a string such as "test query", gets turned into "test+query" which is unacceptable.
URIUtil.encodeQuery()
returns "test%20query" which is almost acceptable, except it needs the %27 at the beginning and end.
When I try to just concatenate the string to make it valid as such, and then load this into URIBuilder, URIBuilder ends up with
https://api.datamarket.azure.com/Data.ashx/Bing/SearchWeb/v1/Web?%24format=json&Query=%2527test%2520query%2527
which is again unacceptable.
How can I remedy this issue? It's driving me insane.
Thanks for any help.
this is encoded URI.
$ is %24
bank is %20
if you want real URI, you need to decode .
I think decode method works well for you.
reference here:
http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/util/URIUtil.html

Encode URL query parameters

How can I encode URL query parameter values? I need to replace spaces with %20, accents, non-ASCII characters etc.
I tried to use URLEncoder but it also encodes / character and if I give a string encoded with URLEncoder to the URL constructor I get a MalformedURLException (no protocol).
URLEncoder has a very misleading name. It is according to the Javadocs used encode form parameters using MIME type application/x-www-form-urlencoded.
With this said it can be used to encode e.g., query parameters. For instance if a parameter looks like &/?# its encoded equivalent can be used as:
String url = "http://host.com/?key=" + URLEncoder.encode("&/?#");
Unless you have those special needs the URL javadocs suggests using new URI(..).toURL which performs URI encoding according to RFC2396.
The recommended way to manage the encoding and decoding of URLs is to use URI
The following sample
new URI("http", "host.com", "/path/", "key=| ?/#ä", "fragment").toURL();
produces the result http://host.com/path/?key=%7C%20?/%23ä#fragment. Note how characters such as ?&/ are not encoded.
For further information, see the posts HTTP URL Address Encoding in Java or how to encode URL to avoid special characters in java.
EDIT
Since your input is a string URL, using one of the parameterized constructor of URI will not help you. Neither can you use new URI(strUrl) directly since it doesn't quote URL parameters.
So at this stage we must use a trick to get what you want:
public URL parseUrl(String s) throws Exception {
URL u = new URL(s);
return new URI(
u.getProtocol(),
u.getAuthority(),
u.getPath(),
u.getQuery(),
u.getRef()).
toURL();
}
Before you can use this routine you have to sanitize your string to ensure it represents an absolute URL. I see two approaches to this:
Guessing. Prepend http:// to the string unless it's already present.
Construct the URI from a context using new URL(URL context, String spec)
So what you're saying is that you want to encode part of your URL but not the whole thing. Sounds to me like you'll have to break it up into parts, pass the ones that you want encoded through the encoder, and re-assemble it to get your whole URL.

Categories