为什么改装无法用方括号正确编码查询字符串



我在Android应用程序中使用网络层的改装,但URL编码有问题。

我必须调用这样的REST API:

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

正如你所看到的,查询字符串是由一些不同类型的参数组成的,所以我决定在改装接口中使用@QueryMap注释和Map<String, String>,其中q, param[1], param[0], other_param是地图的字符串键

我期待什么?我希望URL中的方括号用%5B编码'[',用%5D编码'[',但这并没有发生。

为什么会发生这种情况?方括号应使用百分比编码进行编码。这是bug还是我做错了什么?我还尝试了@EncodedQueryMap注释,没有任何差异。

查询名称从不使用URL编码。

@QueryMap的文档说明:

值是URL编码的。

对于@EncodedQueryMap:

值不是URL编码的。

然而,我只是提交了一个pull请求来稍微改变一下这种行为。我添加了对使用@Query(value = "..", encodeName = true)@QueryMap(encodeNames = true)编码密钥的支持。

我只需要处理除了{}[]之外的所有编码的@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;
}

试试简单的@得到和参数@查询

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

地图包含元素:

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

并且@QueryMap发送

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

QueryMap在那里被使用,因为GET请求中有许多参数,而筛选选项中有对象。

最新更新