【问题标题】:Why Retrofit cannot encode properly query string with square brackets?为什么改造不能用方括号正确编码查询字符串?
【发布时间】:2014-09-30 20:39:51
【问题描述】:

我在我的 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 是地图的字符串键

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

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

【问题讨论】:

  • 看起来你的 rest api 应该期望 params 是一个值数组
  • 我认为你的休息服务器不应该在变量名中使用[],而是在其他任何地方使用它,作为一个列表指示符,在这种情况下括号不应该被编码。
  • 如果不对括号进行编码,服务器 API 将无法正常工作。我需要对括号进行编码,但我想知道如何通过改造而不是手动进行。

标签: java android urlencode retrofit


【解决方案1】:

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

@QueryMap 的文档说明:

值是 URL 编码的。

对于@EncodedQueryMap

值未经过 URL 编码。

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

【讨论】:

  • 这解决了我的情况,我不想对查询值进行编码,所以我设置了 @Query(value = "..", encodeValue = false)
  • 发帖请求呢?
【解决方案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;
}

【讨论】:

  • 如果有人想知道这是添加到OkHttpClient.Builder() 例如。 new OkHttpClient.Builder().addNetworkInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { return null; } });
【解决方案3】:

试试简单的 @得到 和参数@Query

【讨论】:

  • 干净简洁。
【解决方案4】:

此外,如果 value 包含 JSONArray 和 JSONObject,则改造不会编码括号 [ ] { }

地图包含元素:

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

因为 GET 请求中的数字参数和过滤器选项中的对象,所以在此处使用了 QueryMap。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    相关资源
    最近更新 更多