我在Android应用程序中使用网络层的改装,但URL编码有问题。
我必须调用这样的REST API:
https://my_hostname.com/some_path?q=some_query¶m[0]=value1¶m[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请求中有许多参数,而筛选选项中有对象。