"返回response.body()。string()" okhttp3是空的

时间:2016-02-26 10:54:47

标签: android 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":"xxx-ts@laposte.net","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。然后归还它。但是响应是空的。 我无法弄清楚原因。

6 个答案:

答案 0 :(得分:12)

我找到了一个听起来很奇怪的解决方案,至少对我而言。

我改变了课程的结尾如下:

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

所以我把它放在一个变量中,而不是两次调用response.body().string()。 它有效!

答案 1 :(得分:10)

致电response.body().string()消耗身体 - 因此,您无法再次呼叫它。 如果您需要进一步处理,解决方案是将其存储在变量中。

okhttp3中还有一个新方法,即peekBody(byte count),根据文档,它可以从响应主体中查看byteCount字节,并将它们作为新的响应主体返回。

答案 2 :(得分:5)

当您拨打string()并清空支持来源时,您会读取正文。 OkHttp尝试尽快释放支持资源。将正文读入变量是传递它或在多次使用中存储它的正确方法。

通常你不需要关闭身体,但在Android上,我们没有尝试使用资源,我建议最终以手写方式结束。

以下是有关该主题的文档: http://square.github.io/okhttp/3.x/okhttp/

  

响应正文只能被消耗一次。

     

此类可用于传输非常大的响应。例如,可以使用此类来读取大于分配给当前进程的整个内存的响应。它甚至可以传输大于当前设备总存储量的响应,这是视频流应用程序的常见要求。

     

由于此类不会在内存中缓冲完整响应,因此应用程序可能无法重新读取响应的字节。使用这一次使用bytes()或string()将整个响应读入内存。或者使用source(),byteStream()或charStream()来传输响应。

答案 3 :(得分:1)

我们必须将响应内容保存到字符串类型的变量中。

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

答案 4 :(得分:0)

对于Kotlin用户

Dictionary<int, List<Holiday>>

答案 5 :(得分:0)

就我而言,我想走得更远,一只手将响应主体存储为字符串,但又不占用缓冲区,以便能够照常使用它。

我在这里找到了一个有效的解决方案:https://github.com/square/okhttp/issues/2869

基本上,您可以获得缓冲区的只读视图,可以从其中读取而不用它,因此以后仍可以使用。

一段代码:

CREATE EXTENSION pg_trgm;

使用 final BufferedSource source = responseBody.source(); if (!source.request(Integer.MAX_VALUE)) { LOGGER.debug("Error reading response body"); } final String bodyAsStr = source.buffer().snapshot().utf8(); // you can still use your response body as usual responseParser.apply(responseBody.byteStream()) 代替source.string(),该流将为空。