Почему Retrofit не может правильно кодировать строку запроса в квадратных скобках?
Я использую Retrofit для моего сетевого уровня в моем приложении Android, но у меня проблема с кодировкой URL.
Я должен вызвать такой API REST:
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
на '['
, но этого не происходит.
почему это происходит? Квадратные скобки должны быть закодированы с процентной кодировкой. Это ошибка или я делаю что-то неправильно? Я также попробовал @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 и объектов в опции фильтра.