112

I'm trying to get some json data using OkHttp and can't figure out why when i try logging the response.body().toString() what i get is Results:﹕ com.squareup.okhttp.Call$RealResponseBody@41c16aa8

try {
        URL url = new URL(BaseUrl);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .header(/****/)
                .build();

        Call call = client.newCall(request);
        Response response = call.execute();

        **//for some reason this successfully prints out the response**
        System.out.println("YEAH: " + response.body().string());

        if(!response.isSuccessful()) {
            Log.i("Response code", " " + response.code());
        }

        Log.i("Response code", response.code() + " ");
        String results = response.body().toString();

        Log.i("OkHTTP Results: ", results);

Log

I don't know what i'm doing wrong here. How do i get the response string?

freddieptf
  • 2,134
  • 2
  • 15
  • 16
  • Maybe it`s a duplicate of [http://stackoverflow.com/questions/5769717/how-can-i-get-an-http-response-body-as-a-string-in-java](http://stackoverflow.com/questions/5769717/how-can-i-get-an-http-response-body-as-a-string-in-java) – Jens Feb 03 '15 at 13:46
  • You just print an object and your trace confirm it. – Michele d'Amico Feb 03 '15 at 13:49
  • 5
    read the doc. the method you are looking for is `string` – njzk2 Feb 03 '15 at 13:54
  • val responseBodyString = response.body()!!.string() response = response.newBuilder() .body(ResponseBody.create(responseBody?.contentType(), responseBodyString.toByteArray())) .build() – Imran Baig Sep 08 '20 at 12:03
  • Please see this link https://stackoverflow.com/a/70824088/12272687 – Mori Jan 23 '22 at 16:18

10 Answers10

305

You have use .string() function to print the response in System.out.println(). But at last in Log.i() you are using .toString().

So please use .string() on response body to print and get your request's response, like:

response.body().string();

NOTE:

  1. .toString(): This returns your object in string format.

  2. .string(): This returns your response.

I think this solve your problem... Right.

V.J.
  • 9,492
  • 4
  • 33
  • 49
55

Just in case someone bumps into the same weird thing as I have. I run my code during development in Debug Mode and apparently since OKHttp 2.4

..the response body is a one-shot value that may be consumed only once

So when in debug there is a call "behind the scene" from the inspector and the body is always empty. See: https://square.github.io/okhttp/3.x/okhttp/okhttp3/ResponseBody.html

Oded Regev
  • 4,065
  • 2
  • 38
  • 50
  • Dead link. Use this one ==> http://square.github.io/okhttp/2.x/okhttp/com/squareup/okhttp/Response.html – mrroboaat Dec 08 '15 at 14:37
  • 3
    how do you call `.string()` without consuming response body? – osrl Dec 30 '15 at 08:01
  • 1
    Not sure if you can call .string() without consuming the response body, but as a workaround, but you can follow the pattern that okhttp's logging interceptor use to do this: https://github.com/square/okhttp/blob/master/okhttp-logging-interceptor/src/main/java/okhttp3/logging/HttpLoggingInterceptor.java#L237-L266 – liampronan Jun 19 '16 at 04:55
  • 1
    It means that we can't debug Okhttp response body –  Aug 16 '16 at 05:52
  • 1
    You can print the response body to Log with debug disabled – Oded Regev Aug 16 '16 at 07:13
  • 4
    What a wicked behavior! I know how unhelpful this sort of comments is, want to thank you nevertheless – Sergei Voitovich Jun 05 '20 at 19:36
  • @OdedRegev life savior! – Avik Aggarwal Nov 19 '20 at 17:14
  • If you want to access the response body multiple times (e.g. when debugging) see this answer: https://stackoverflow.com/a/33862068/2011622 – Peter F Feb 12 '21 at 17:05
20

The response.body.string() can be consumed only once. Please use as below:

String responseBodyString = response.body.string();

Use the responseBodyString as needed in your application.

Laurel
  • 5,965
  • 14
  • 31
  • 57
  • 1
    This may trigger an **OutOfMemoryError** for a large response (i.e. zip file) – IgorGanapolsky Jun 11 '18 at 13:57
  • Typo with comma inside your 1st line's code-span, should be `response.body.string()`. The hint in your code-block should be out-commented, e.g. prefix with `//`. – hc_dev May 31 '22 at 23:16
2

Given that a response can potentially produce an OutOfMemoryError in cases of large files, you can instead "peek" the body with the number of bytes and call the string() method.

Note that this will consume the body.

response.peekBody(500).string());

riddle_me_this
  • 8,575
  • 10
  • 55
  • 80
2

Following is my modified CurlInterceptor. Check the end of the intercept function where I m recreating the Response object after consuming the old Response.

var responseBodyString = responseBody?.string()

response = response.newBuilder() .body( ResponseBody.create( responseBody?.contentType(), responseBodyString.toByteArray() ) ) .build()

class CurlInterceptor: Interceptor
{

    var gson = GsonBuilder().setPrettyPrinting().create()

    override fun intercept(chain: Interceptor.Chain): Response {

    Timber.d(" **** ->>Request to server -> ****")

    val request = chain.request()
    var response = chain.proceed(request)

    var curl = "curl -v -X  ${request.method()}"

    val headers = request.headers()

    for ( i in 0..(headers.size() -1) ){
        curl = "${curl} -H \"${headers.name(i)}: ${headers.value(i)}\""
    }

    val requestBody = request.body()
    if (requestBody != null) {
        val buffer = Buffer()
        requestBody.writeTo(buffer)
        var charset: Charset =
            Charset.forName("UTF-8")
        curl = "${curl} --data '${buffer.readString(charset).replace("\n", "\\n")}'"
    }

    Timber.d("$curl ${request.url()}")
    Timber.d("response status code ${response.code()} message: ${response.message()}")

    
    dumbHeaders(response)

    var responseBody = response?.body()

    if(responseBody != null )
    {
        var responseBodyString = responseBody?.string()

            response = response.newBuilder()
                .body(
                    ResponseBody.create(
                        responseBody?.contentType(),
                        responseBodyString.toByteArray()
                    )
                )
                .build()


        responseBodyString = gson.toJson(responseBodyString)

        Timber.d("response json -> \n $responseBodyString")

    }

    Timber.d(" **** << Response from server ****")

    return response
}



fun dumbHeaders(response: Response) {
    try {
        if (response.headers() != null) {

            for (headerName in response.headers().names()) {
                for (headerValue in response.headers(headerName)) {
                    Timber.d("Header $headerName : $headerValue")
                }
            }
        }
    }
catch (ex: Exception){}
}
}
Imran Baig
  • 357
  • 3
  • 4
2

Instead of using .toString() which returns an object

String results = response.body().toString();

you can use

String results = response.body().string();
1
   Call call = client.newCall(request);
   return call.execute().body().string();

we can get response as a return fromby these

  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 02 '22 at 15:32
0

try to change it like that for example:

protected String doInBackground(String... params) {
            try {
                JSONObject root = new JSONObject();
                JSONObject data = new JSONObject();
                data.put("type", type);
                data.put("message", message);
                data.put("title", title);
                data.put("image_url", imageUrl);
                data.put("uid",uid);
                data.put("id", id);
                data.put("message_id", messageId);
                data.put("display_name", displayName);
                root.put("data", data);
                root.put("registration_ids", new JSONArray(receipts));
                RequestBody body = RequestBody.create(JSON, root.toString());
                Request request = new Request.Builder()
                        .url(URL)
                        .post(body)
                        .addHeader("Authorization", "key=" + serverKey)
                        .build();
                Response response = mClient.newCall(request).execute();
                String result = response.body().string();
                Log.d(TAG, "Result: " + result);
                return result;
            } catch (Exception ex) {
                Log.e(TAG,"Exception -> "+ex.getMessage());
            }
            return null;
        }
  • 1
    Code-only answers are discouraged. Please click on [edit] and add some words summarising how your code addresses the question, or perhaps explain how your answer differs from the previous answer/answers. Thanks – Nick Jan 03 '19 at 00:28
0

Recreate the response object after consuming the string

val responseBodyString = response.body()!!.string()

response = response.newBuilder() .body(ResponseBody.create(responseBody?.contentType(), responseBodyString.toByteArray())) .build()

Imran Baig
  • 357
  • 3
  • 4
0

Kotlin Programmers I am here for you

 response.body?.charStream()?.readText()?.let { 
                        //Where it refers to Response string
                        callBack.onAPISuccess(it)
                    }

Here you can not use .toString() function and .string() function is not available in Kotlin than you can user charStream() and than convert that charStream into readText() but you have to unwrap the whole value before passing it.But it will never create problem.

I have not explored these charStream() and readText() functions in java but I think it should be there and you can use this in java if these functions are available because I just got to know that java has deprecated the .string() function.