Why Retrofit cannot encode properly query string with square brackets?

落爺英雄遲暮 提交于 2019-12-06 23:43:07

问题


I'm using Retrofit for my network layer in my Android app, but I have a problem with the URL encoding.

I have to call an REST API like that:

https://my_hostname.com/some_path?q=some_query&param[0]=value1&param[1]=value2&other_param=abcd

as you can see the query string is composed by some different kind of parameters, so I decided to use the @QueryMap annotation in the Retrofit Interface with a Map<String, String> where q, param[1], param[0], other_param are String keys of the map

What do I expect? I expect the square brackets in the URL are encoded with %5B for '[' and %5D for '[', but this does not happen.

Why does this happen? The square brackets should be encoded with percent encoding. Is this a bug or I'm doing something wrong? I also tried the @EncodedQueryMap annotation with no differences.


回答1:


Query names are never URL encoded.

The documentation for @QueryMap states:

Values are URL encoded.

And for @EncodedQueryMap:

Values are not URL encoded.

However, I just submitted a pull request to change this behavior a bit. I am adding support for encoding keys by using @Query(value = "..", encodeName = true) or @QueryMap(encodeNames = true).




回答2:


I just had to deal with @QueryMap encoding everything but {}[]. Most of the time I don't mind because I rarely send json in the query, and want to push the encoding down as low as possible in my application's stack, but recently I had to add an endpoint just like Ivan describes. My solution was to add an interceptor that does this:

Request originalRequest = chain.request();
HttpUrl url = originalRequest.url();
String urlFilePath = url.encodedPath();
if(url.encodedQuery() != null) {
    // Because Retrofit doesn't think "{}[]" should be encoded
    // but our API does
    String correctlyEncodedQuery = correctlyEncodeQuery(url);
    urlFilePath += "?" + correctlyEncodedQuery;
}
URL correctUrl = new URL(url.scheme(), url.host(), url.port(),
        urlFilePath);
Request newRequest = originalRequest.newBuilder()
        .url(correctUrl)


private String correctlyEncodeQuery(HttpUrl url) throws UnsupportedEncodingException {
    String retVal = "";
    for(String queryKey : url.queryParameterNames()){
        if(retVal.length() > 0){
            retVal += "&";
        }
        String queryValue = url.queryParameter(queryKey);
        retVal += queryKey + "=" + URLEncoder.encode(queryValue, "utf-8");
    }
    return retVal;
}



回答3:


Try simple one @GET and parameters @Query




回答4:


Moreover, if value contains JSONArray with JSONObject, retrofit doesn't encode brackets [ ] { }

Map contains element:

key = filter, 
value = [{"field":"some_field","value":"some_value","operator":"="}]

And @QueryMap send

http://my_server/api?filter=[{%22field%22:%22some_field%22,%22value%22:%22some_value%22,%22operator%22:%22%3D%22}]

QueryMap used there because of number params in GET request and objects in filter option.



来源:https://stackoverflow.com/questions/26129697/why-retrofit-cannot-encode-properly-query-string-with-square-brackets

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