为什么Retrofit无法使用方括号正确编码查询字符串?

时间:2014-09-30 20:39:51

标签: java android urlencode retrofit

我在Android应用中使用Retrofit作为我的网络层,但我对URL编码有疑问。

我必须像这样调用REST API:

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

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

我期待什么? 我希望网址中的方括号使用%5B '['%5D '['进行编码,但这不会发生。

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

4 个答案:

答案 0 :(得分:13)

查询名称永远不会进行URL编码。

@QueryMap州的文档:

  

值是URL编码。

对于@EncodedQueryMap

  

值不是URL编码。

但是,我只是submitted a pull request来改变这种行为。我正在使用@Query(value = "..", encodeName = true)@QueryMap(encodeNames = true)添加对密钥编码的支持。

答案 1 :(得分:2)

除了@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;
}

答案 2 :(得分:1)

尝试简单的一个 @得到 和参数@Query

答案 3 :(得分:1)

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

地图包含元素:

end_date

和@QueryMap发送

key = filter, 
value = [{"field":"some_field","value":"some_value","operator":"="}]
由于GET请求中的数字参数和过滤器选项中的对象,

在那里使用了QueryMap。