Почему Retrofit не может правильно кодировать строку запроса в квадратных скобках?

Я использую Retrofit для моего сетевого уровня в моем приложении Android, но у меня проблема с кодировкой URL.

Я должен вызвать такой API REST:

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 на '[', но этого не происходит.

почему это происходит? Квадратные скобки должны быть закодированы с процентной кодировкой. Это ошибка или я делаю что-то неправильно? Я также попробовал @EncodedQueryMap Примечания без разницы.

4 ответов


имена запросов никогда не кодируются URL.

документация @QueryMap гласит:

значения кодируются URL.

и @EncodedQueryMap:

значения не кодируются URL.

, просто подан запрос на вытягивание чтобы немного изменить это поведение. Я добавляю поддержку ключей кодирования с помощью @Query(value = "..", encodeName = true) или @QueryMap(encodeNames = true).

мне просто пришлось иметь дело с @QueryMap кодировка все, кроме {}[]. Большую часть времени я не возражаю, потому что я редко отправляю JSON в запросе и хочу как можно ниже продвинуть кодировку в стеке моего приложения, но недавно мне пришлось добавить конечную точку, как описывает Иван. Мое решение состояло в том, чтобы добавить перехватчик, который делает это:

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

попробуйте простой @ПОЛУЧИТЬ и параметры запроса@


кроме того, если значение содержит JSONArray с JSONObject, retrofit не кодирует скобки [ ] { }

карта содержит элемента:

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 и объектов в опции фильтра.