我在Android应用中使用Retrofit作为我的网络层,但我对URL编码有疑问。
我必须像这样调用REST API:
https://my_hostname.com/some_path?q=some_query¶m[0]=value1¶m[1]=value2&other_param=abcd
正如您所看到的,查询字符串由一些不同类型的参数组成,因此我决定在Retrofit Interface中使用@QueryMap
注释Map<String, String>
q, param[1], param[0], other_param
是地图的字符串键
我期待什么?
我希望网址中的方括号使用%5B
'['
和%5D
'['
进行编码,但这不会发生。
为什么会这样?方括号应使用百分比编码进行编码。这是一个错误还是我做错了什么?我也尝试了@EncodedQueryMap
注释没有任何区别。
答案 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。