【问题标题】:Retrofit 2: @Query "encoded=false" don't work改造 2:@Query "encoded=false" 不起作用
【发布时间】:2026-01-02 10:55:02
【问题描述】:

0) 我正在使用 Retrofit 2 来处理 Bank API
1)我有一些界面:

public interface ApiService {
    @GET("statdirectory/exchange")
    Call<List<MyModel>>  getСurrency(@Query("date") String inputDate);
}

2) 当我调用 getСurrency(someParametr) 方法时,其中 someParametr 是字符串,包含“date&json”(例如,“20170917&json”):

ApiService apiService = RetrofitController.getApi();
apiService.getCurrency("20170917&json").enqueue(new Callback<List<MyModel>>() {

      @Override
      public void onResponse(Call<List<MyModel>> call, Response<List<MyModel>> response) {
          call.request().url();
          Log.e("URL",  call.request().url()+"");
          response.code();
          Log.e("CODE", response.code()+"");      
}
//.....

3) 我明白了:
URL:"https://bank.gov.ua/NBUStatService/v1/statdirectory/exchange?date=20170917%26json"&%26代替)
代码:“404”
4)我的界面我添加了encoded

getСurrency(@Query(value="date", encoded=false) String inputDate);

我的结果与第 3 步中的结果相同

5) 如何检查这个问题?如何在我的字符串上获取没有 %26 的 URL?我阅读了其他类似问题的问题,但没有解决我的问题。谢谢!

【问题讨论】:

  • 为什么会出现这个问题?为什么你有一个没有值的参数json
  • @TimCastelijns,我的完整代码是有效的,但我不知道为什么我的 URL 20170917&json 编码为 20170917%26json 以及如何修复它.
  • 您要解决什么问题?你知道什么是url编码吗?
  • @TimCastelijns,对url编码有点熟悉。我能用这个做什么?
  • @Tomas 您需要手动构建 url 查询将无法正常工作,如我帖子中指出的 github 问题中所述

标签: java android json retrofit2


【解决方案1】:

我只是想澄清一下,最初的问题是编码参数必须为真:encoded=true。这表明提供的值已经编码,因此不需要通过改造重新编码。如改造文档中所述,encoded 的默认值为 false。即:

getСurrency(@Query(value="date", encoded=true) String inputDate);

将导致生成正确的 url。

文档中关于encoded 参数的说明如下:

指定参数名和值是否已经是URL 编码。

来源:https://square.github.io/retrofit/2.x/retrofit/index.html?retrofit2/http/Query.html

【讨论】:

    【解决方案2】:

    正如此处https://github.com/square/okhttp/issues/2623 swankjesse 所述

    使用HttpUrl 构建网址

    HttpUrl url = HttpUrl.parse("https://bank.gov.ua/NBUStatService/v1/statdirectory/exchange?date=20170916&json");
    

    然后将您的方法调用更改为

    @GET
    Call<List<MyModel>>  getСurrency(@Url String ur);
    

    然后

     apiService.getCurrency(url.toString())
           .enqueue(new Callback<List<MyModel>>() {
    
            @Override
            public void onResponse(Call<List<MyModel>> call, retrofit2.Response<List<MyModel>> response) {
                // your response
            }
    
            @Override
            public void onFailure(Call<List<MyModel>> call, Throwable t) {
    
            }
    
        });
    

    另一种方法是使用Okhttp的Interceptor并将%26替换为&

    class MyInterceptor implements Interceptor {
       @Override
       Response intercept(Interceptor.Chain chain) throws IOException {
        Request request = chain.request()
        String stringurl = request.url().toString()
        stringurl = stringurl.replace("%26", "&")
    
        Request newRequest = new Request.Builder()
            .url(stringurl)
            .build()
    
        return chain.proceed(newRequest)
     }
    }
    

    然后

     OkHttpClient client = new OkHttpClient.Builder();
     client.addInterceptor(new MyInterceptor());
    

    【讨论】:

    • 谢谢您的回答!!!这对我有用!)但我有一个问题......如何使用“Okhttp's Interceptor”的第二种方式?我在哪里覆盖了intercept 方法?
    【解决方案3】:

    如果您仍然遇到此问题,我有 2 个解决方案。

    第一个解决方案:

    // Create a URL object and pass to constructor your url
    URL urlObject = new URL(url);
    // Create connection
    HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
    // SET 'GET' request
    connection.setRequestMethod("GET");
    connection.connect();
    // Create stream to read output
    InputStream inputStream = connection.getInputStream();
    
    // Craete buffer to gain all output
    StringBuffer stringBuffer = new StringBuffer();
    AND HERE IS THE KEY
    YOU CREATE A BUFFERREADER AND SET CP1251 SO URL`S GONNA BE ENCODED
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "cp1251"));
    // Read untill end
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        stringBuffer.append(line);
    }
    // HERE IS YOUR JSON RESULT
    resultJson = stringBuffer.toString();
    

    第二种解决方案:

    只需将encoded = true 添加到您的@Query 注释中

    @GET("some_path")
        Call<RequestBody> function(@Query(value = "param", encoded = true) String your_param);
    

    就是这样!所有这些对我来说都很好。如果您有一些问题或问题,我会回答。

    【讨论】:

      【解决方案4】:

      您的 Json 将具有键值数据。尝试以以下格式传递。 它会在 Json 键前自动添加&amp;

      getСurrency(@Query("date") String inputDate, @Query("key1") String value1, @Query("key2") String value2);
      

      【讨论】: