return response.body().string() пуст с okhttp3

Я создал следующий класс:

package com.inverseo.marc.t372lematin;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


public class PostJSON {
    public static final MediaType JSON
            = MediaType.parse("application/json; charset=utf-8");

    OkHttpClient client = new OkHttpClient();
    public String postJSONRequest(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        Response response = client.newCall(request).execute();
        System.out.println("postJSONRequest response.body : "+response.body().string());
        return response.body().string() ;
    }   //postJSONRequete
} //class PostJSON

Раньше он работал из действия, когда я пишу некоторые данные в MySQL на сервере. И когда я вызываю его из следующего фрагмента кода, я получаю пустой ответ!

      System.out.println("début appel "+getString(R.string.CF_URL)+"authentication2.php" );
        PostJSON client2 = new PostJSON();
        JSONObject obj = new JSONObject();
        try {
            obj.put("username", mUserName);
            obj.put("password", mPassword);
            obj.put("email", mEmail);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        System.out.println("obj.toString()="+obj.toString());
        String response = null;
        try {
            response = client2.postJSONRequest(getString(R.string.CF_URL)+ "authentication2.php", obj.toString());
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("appel d'authentication2.php échoué : " + e);
        }
        System.out.println("fin authentication2, response = "+response);
        return response;

Вот что я получаю в logcat

02-25 05:52:24.938 26130-26226/com.inverseo.marc.t372lematin I/System.out: Accès à Internet : OK
02-25 05:52:24.938 26130-26226/com.inverseo.marc.t372lematin I/System.out: début appel http://mywebsite.fr/Inverseo/authentication2.php
02-25 05:52:24.938 26130-26226/com.inverseo.marc.t372lematin I/System.out: obj.toString()={"email":"[email protected]","password":"xxx","username":"MarcUser"}
02-25 05:52:25.068 26130-26130/com.inverseo.marc.t372lematin I/Choreographer: Skipped 30 frames!  The application may be doing too much work on its main thread.
02-25 05:52:25.448 26130-26130/com.inverseo.marc.t372lematin I/Choreographer: Skipped 34 frames!  The application may be doing too much work on its main thread.
02-25 05:52:27.898 26130-26226/com.inverseo.marc.t372lematin I/System.out: postJSONRequest response.body : {"result":1,"message":"AUTHENTICATION OK","Id_profile":"1394","DebutDerCycle":"2016-01-31"}
02-25 05:52:27.898 26130-26226/com.inverseo.marc.t372lematin I/System.out: fin authentication2, response = 
02-25 05:52:28.588 26130-26130/com.inverseo.marc.t372lematin I/Choreographer: Skipped 140 frames!  The application may be doing too much work on its main thread.

Итак, чтобы подвести итог, в моем классе PostJSON я записываю правильный результат в System.out. Затем верните его. Но тогда ответ пустой. Я не могу понять, почему.


person Marc    schedule 26.02.2016    source источник


Ответы (6)


Я нашел решение, которое звучит странно, по крайней мере, для меня.

Я изменил конец класса следующим образом:

String MyResult = response.body().string();
System.out.println("postJSONRequest response.body : "+MyResult);
return MyResult ;

Поэтому вместо того, чтобы дважды вызывать response.body().string(), я поместил его в переменную. И это работает!

person Marc    schedule 26.02.2016
comment
Вы правы, это странно. Но это также то, как работает OkHttp (по дизайну). Как только вы вызываете response.body().string(), информация очищается, что означает, что при втором вызове вы ничего не получите. - person portfoliobuilder; 25.06.2019
comment
За источником у вас есть буфер, string() потребляет его, поэтому любой последующий вызов не находит ничего для потребления. Если вы хотите читать несколько раз, вы можете использовать класс Relay. - person Alessandro S.; 02.10.2020

Вызов response.body().string() потребляет тело — поэтому вы не можете вызвать его во второй раз. Решение состоит в том, чтобы сохранить его в переменной, если он вам нужен для дальнейшей обработки.

Существует также новый метод, доступный в okhttp3, и это peekBody(byte count), который, согласно документации, просматривает байты byteCount из тела ответа и возвращает их как новое тело ответа.

person MarkoMilos    schedule 16.03.2016

Вы прочитали тело, когда вызвали string() и очистили резервный источник. OkHttp пытается освободить резервный ресурс как можно скорее. Чтение тела в переменную — это правильный способ передать или сохранить его более чем за одно использование.

Обычно вам не нужно закрывать тело, но на Android, где у нас нет try-with-resources, я бы рекомендовал закрывать окончательно написанное от руки.

Вот документы по этому вопросу: http://square.github.io/okhttp/3.x/okhttp/

Тело ответа можно использовать только один раз.

Этот класс можно использовать для потоковой передачи очень больших ответов. Например, этот класс можно использовать для чтения ответа, размер которого превышает всю память, выделенную текущему процессу. Он может даже передать ответ, превышающий общий объем памяти на текущем устройстве, что является общим требованием для приложений потоковой передачи видео.

Поскольку этот класс не буферизует полный ответ в памяти, приложение может не перечитать байты ответа. Используйте этот один выстрел, чтобы прочитать весь ответ в память с помощью bytes() или string(). Или выполните потоковую передачу ответа с помощью source(), byteStream() или charStream().

person user823629    schedule 21.06.2016

Мы должны сохранить содержимое ответа в переменную строкового типа.

OkHttpClient client = new OkHttpClient();

    try{
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, "'{\"id\":\"10001\"}'");
        Request request = new Request.Builder()
                .url("mydomain")
                .post(body)
                .addHeader("content-type", "application/json")
                .addHeader("cache-control", "no-cache")
                .build();

        Response response= client.newCall(request).execute();
        String MyResult = response.body().string();
        return MyResult;
    }catch (Exception ex){
        return  ex.toString();
    }
person Jorge Santos Neill    schedule 24.10.2017


Для пользователей Котлин

val topNewsList = gson.fromJson(body, NewsList::class.java)

getActivity()?.runOnUiThread {
    try {

       if(topNewsList.post_data != null) {
          //set adapter
          recyclerView_news.adapter = TopNewsAdapter(topNewsList, layout.row_news)
       }
       else{
          // handle the empty list
       }

   } 
   catch (e: Exception) {
    Toast.makeText(context, "Please refresh again", Toast.LENGTH_SHORT).show()
  }
}
person santosh devnath    schedule 09.08.2019