java 为什么 Retrofit 不能正确编码带方括号的查询字符串?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26129697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 09:20:02  来源:igfitidea点击:

Why Retrofit cannot encode properly query string with square brackets?

javaandroidurlencoderetrofit

提问by Noodles

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

我在我的 Android 应用程序中为我的网络层使用 Retrofit,但我遇到了 URL 编码问题。

I have to call an REST API like that:

我必须像这样调用 REST API:

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 @QueryMapannotation in the Retrofit Interface with a Map<String, String>where q, param[1], param[0], other_paramare String keys of the map

正如您所看到的,查询字符串由一些不同类型的参数组成,因此我决定使用@QueryMapRetrofit Interface 中的注释,Map<String, String>其中 q, param[1], param[0], other_param包含地图的字符串键

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

我期待什么?我希望 URL 中的方括号用%5Bfor'['%5Dfor编码'[',但这不会发生。

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 @EncodedQueryMapannotation with no differences.

为什么会发生这种情况?方括号应使用百分比编码进行编码。这是一个错误还是我做错了什么?我也尝试了@EncodedQueryMap没有区别的注释。

回答by Jake Wharton

Query names are never URL encoded.

查询名称从不进行 URL 编码。

The documentation for @QueryMapstates:

@QueryMap状态的文档:

Values are URL encoded.

值是 URL 编码的。

And for @EncodedQueryMap:

而对于@EncodedQueryMap

Values are not URL encoded.

值不是 URL 编码的。

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

但是,我只是提交了一个拉取请求来稍微改变这种行为。我正在通过使用@Query(value = "..", encodeName = true)或添加对编码密钥的支持@QueryMap(encodeNames = true)

回答by etherton

I just had to deal with @QueryMapencoding 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:

我只需要处理@QueryMap所有内容的编码,但{}[]. 大多数时候我不介意,因为我很少在查询中发送 json,并且希望在我的应用程序堆栈中尽可能降低编码,但最近我不得不像 Ivan 描述的那样添加一个端点。我的解决方案是添加一个执行此操作的拦截器:

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;
}

回答by Swapnil Kshirsagar

Try simple one @GET and parameters @Query

尝试简单的@GET 和参数@Query

回答by Ivan Trechyokas

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

此外,如果 value 包含带有 JSONObject 的 JSONArray,retrofit 不会编码方括号 [] { }

Map contains element:

地图包含元素:

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

And @QueryMap send

和@QueryMap 发送

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.

由于 GET 请求中的数字参数和过滤器选项中的对象,在那里使用了 QueryMap。