Encoding curly braces in Jersey Client 2

ぃ、小莉子 提交于 2020-01-23 07:55:11

问题


We are using Jersey Client 2.21. I am noticing that when we put curly braces (aka curly brackets) as a param value, then it does not get properly encoded. Not only that, but anything inside the curly braces does not get encoded either. This is not true for regular brackets or other unsafe characters that I have tested with.

Please see the example below. In this example I enter three params. A control param with just spaces. One with curly braces, and one with regular brackets.

public static void testJerseyEncoding() {
    Client client = ClientBuilder.newClient();
    String url = "http://foo.com/path";
    Map<String, String> map = new HashMap<>();
    map.put("paramWithCurly", " {with a space}");
    map.put("paramWithOutCurly", "with a space");
    map.put("paramWithBracket", "[with a space]");
    WebTarget target = client.target(url);
    for (Map.Entry<String, String> entry : map.entrySet()) {
        target = target.queryParam(entry.getKey(), entry.getValue());
    }
    System.out.println(target.toString());
}

Here is the output:

JerseyWebTarget { http://foo.com/path?paramWithBracket=%5Bwith+a+space%5D&paramWithOutCurly=with+a+space&paramWithCurly=+{with a space} }

Is something broken with the Jersey Client or am I missing something? The curly braces should have been encoded to "%7B".


回答1:


When you create a parameter with a value in curly, Jersey thinks you want to use a URL parameter. See https://jersey.github.io/documentation/latest/uris-and-links.html.

UriBuilder.fromUri("http://localhost/")
 .path("{a}")
 .queryParam("name", "{value}")
 .build("segment", "value");

So you should encode curly braces yourselves via URLEncoder, probably as described there: How to force URIBuilder.path(...) to encode parameters like "%AD"? This method doesn't always encode parameters with percentage, correctly.




回答2:


Instead of manually pre-encoding the query parameter value, a better way might be do always use a template parameter and then use resolveTemplate() with the un-safe value.

Client client = ClientBuilder.newClient();

WebTarget target = client.target("http://server")
            .path("/foo")
            .queryParam("bar", "{bar}")
            .resolveTemplate("bar", "{\"foo\":\"bar\"}");

assertThat(target.getUri().toString())
        .isEqualTo("http://server/foo?bar=%7B%22foo%22%3A%22bar%22%7D");



回答3:


So, first of all it's insane that Jersey is doing templating by default. Secondly, all the solutions here are wrong...doing URLEncoder.encode(..., "UTF-8") will not work for query params which contains spaces. Since the URLEncoder will encode the space as +, which Jersey will interpret as a plus sign, so Jersey ends up encoding it as %2B. See https://docs.oracle.com/javase/7/docs/api/java/net/URLEncoder.html for reference.

My proposed solution, which I'm not very happy with (as always with Java) is to replace all { and } with %7B and %7D respectively, as following:

Map<String, String> map = new HashMap<>();
map.put("paramWithCurly", " {with a space}".replaceAll("\\{", "%7B").replaceAll("\\}", "%7D"));
map.put("paramWithOutCurly", "with a space");
map.put("paramWithBracket", "[with a space]");
WebTarget target = client.target(url);
for (Map.Entry<String, String> entry : map.entrySet()) {
    target = target.queryParam(entry.getKey(), entry.getValue());
}



回答4:


You could solve this problem by using URLEncoder.encode( "..." , "UTF-8") method

String java.net.URLEncoder.encode(String s, String enc) throws UnsupportedEncodingException

Translates a string into application/x-www-form-urlencoded format using a specific encoding scheme. This method uses the supplied encoding scheme to obtain the bytes for unsafe characters.

update your code by using URLEncoder.encode

    try { 
        map.put("paramWithCurly", URLEncoder.encode(" {with a space}", "UTF-8"));
        map.put("paramWithOutCurly", URLEncoder.encode("with a space", "UTF-8"));
        map.put("paramWithBracket", URLEncoder.encode("[with a space]", "UTF-8"));
    } catch (UnsupportedEncodingException e1) {
         System.err.println("........");
    }

Here is the output:

JerseyWebTarget { http://foo.com/path?paramWithBracket=%5Bwith%2Ba%2Bspace%5D&paramWithOutCurly=with%2Ba%2Bspace&paramWithCurly=%2B%7Bwith%2Ba%2Bspace%7D }

Hint:-

using UTF-8 as the encoding scheme the string "The string ü@foo-bar" would get converted to "The+string+%C3%BC%40foo-bar" 

Reference: https://stackoverflow.com/a/607403/6638958




回答5:


It seems that Karim's solution above will not work, exactly as predicted by Tapped. The spaces were encoded as plus signs by URLEncoder.encode which were then encoded by Jersey to %2B characters which is incorrect.



来源:https://stackoverflow.com/questions/35659273/encoding-curly-braces-in-jersey-client-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!