ANDROID - 如何使用OkHTTPClient正确执行HTTP请求

时间:2016-06-08 15:31:08

标签: android rest http okhttp

我正在开发Android应用程序,当我试图访问我的API时,我遇到了一个奇怪的错误。我在AsyncTask对象中使用了okhttp执行方法,并且我通过自定义界面将消息检索到UI。对于第一个请求,解决方案就像一个魅力,但当我试图执行第二个时,应用程序死了,出现以下错误:

  

引起:java.lang.IllegalStateException:已关闭

     
    

at okhttp3.internal.http.Http1xStream $ ChunkedSource.read(Http1xStream.java:418)

  

当我从OKHTTP文档中读出它时,如果我试图两次调用responseBody.string(),则会出现此错误。 (Link to documentation)

老实说我不知道​​根本原因是什么,因为我只在asyctask中调用body()。string()一次,并且我在每次点击都创建一个新的Request实例。从我的角度来看,一个Request实例等于一个处理(和缓冲区关闭),如果我创建另一个请求,那么它应该从开始,另一个响应对象和另一个响应体开始。

请您查看我的代码,找出问题所在?

这是我的AsyncTask的受影响部分:

@Override
protected String doInBackground(Request... params) {
    Request req = params[0];
    try {
        Response resp = httpClient.newCall(req).execute();
        return resp.body().string();

    } catch (IOException e) {
        Log.e(TAG, "IOException occured :" + e.getMessage());
    }finally {

    }
    return null;
}

@Override
protected void onProgressUpdate(String... values) {

}

@Override
protected void onPostExecute(String response) {
    if(response != null){
        callback.onResponseReceived(response);
    }else{
        callback.onConnectionError(new NullPointerException("Empty response after requesting data from medev.hu!"));
    }
}

这就是我从UI线程调用的内容:

  private void ContentProvRequest(String operation, String params, CredentialsProvider credentialsProvider, HTTPResponseListener callback){

    Request request = new Request.Builder().
            url(ContentProviderURL + "?operation=" + operation + "&params=" + params).
            addHeader("Cache-control", "no-cache").
            addHeader("Authorization", "Bearer " + getJWT()).
            addHeader("Accept-Encoding", "UTF-8").
            get().
            build();

    loginInterceptor.setCredentialsProvider(credentialsProvider);

    APIRequest apiRequest = new APIRequest(httpClient,callback,securePreferences);
    apiRequest.execute(request);
}

这是httpclient配置:

 public RemoteDBAdapter(MainActivity activity) {
    this.mActivity = activity;
    securePreferences= activity.getSecurePref();

    ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
            .tlsVersions(TlsVersion.TLS_1_2)
            .cipherSuites(
                    CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
            )
            .build();

    loginInterceptor = new LoginInterceptor(securePreferences);

    httpClient = new OkHttpClient.Builder()
            .followRedirects(true)
            .addInterceptor(loginInterceptor)
            .connectionSpecs(Collections.singletonList(spec))
            .build();
}

LoginInterceptor.java:

public class LoginInterceptor implements Interceptor {
 public static String TAG = "HTTPInterceptor";

 private Chain mChain;
 private SharedPreferences securePreferences;
 private CredentialsProvider credentialsProvider;


 public LoginInterceptor(SharedPreferences sharedPreferences) {
     this.securePreferences = sharedPreferences;
 }

 public void setCredentialsProvider(CredentialsProvider credentialsProvider){
     this.credentialsProvider = credentialsProvider;
 }


 @Override
 public Response intercept(Chain chain) throws IOException {
     this.mChain = chain;

     Request origRequest = chain.request();

     Response origResponse = chain.proceed(origRequest);

     if(origResponse.code() == 401){
         RemoteDBAdapter.setJWT(getToken());
         Log.i(TAG, "New TOKEN :  " + RemoteDBAdapter.getJWT());

         Request newRequest = new Request.Builder().
                 url(origRequest.url()).
                 addHeader("Cache-control", "no-cache").
                 addHeader("Authorization", "Bearer " + RemoteDBAdapter.getJWT()).
                 addHeader("Accept-Encoding", "UTF-8").
                 build();


         Response newResponse = chain.proceed(newRequest);

         return newResponse;
     }else{
         Log.i(TAG, "Token is still valid. Refresh skipped. " + origResponse.body().string());
         return origResponse;
     }
 }



 private String getToken(){

     Log.i(TAG, "Requesting new Token...");

     String usrname;
     String passwd;

     if(credentialsProvider != null){
         usrname = credentialsProvider.getUserName();
         passwd = credentialsProvider.getPassword();
     }else{
         usrname = securePreferences.getString(MainActivity.KEY_USERNAME,"None");
         passwd = securePreferences.getString(MainActivity.KEY_PASSWD,"None");
     }

     RequestBody body = new FormBody.Builder().
             add("useremail", usrname.replace("/", "@")).
             add("password", passwd).
             build();

     Request tokenRequest = new Request.Builder().
             url(RemoteDBAdapter.TokenProviderURL).
             addHeader("Cache-control", "no-cache").
             addHeader("Content-Type", "application/x-www-form-urlencoded").
             addHeader("Accept-Encoding", "UTF-8").
             cacheControl(CacheControl.FORCE_NETWORK).
             post(body).
             build();

     Response tokenResponse = null;

     String jwtString = "";
     try {
         tokenResponse = mChain.proceed(tokenRequest);
         String jsonString = tokenResponse.body().string();
         Log.i(TAG, "Response from the server:  (" + tokenResponse.code() + ") " + jsonString);

         JSONObject responseInJSON = new JSONObject(jsonString);
         Log.i(TAG, "Token refreshed!");

         jwtString = responseInJSON.getString("jwt");

     } catch (IOException e) {
         Log.e(TAG, "IOException: " + e.getMessage());
     } catch (JSONException e) {
         Log.e(TAG, "JSONException: " + e.getMessage());
     } catch (NullPointerException e){
         Log.e(TAG, "NullPointerException: " + e.getMessage());
     }


     return jwtString;
 }
}

完整的堆栈跟踪:

   FATAL EXCEPTION: AsyncTask #3
           Process: hu.medev.projects.myapplication, PID: 11094
    java.lang.RuntimeException: An error occured while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:300)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
        at java.lang.Thread.run(Thread.java:818)
     Caused by: java.lang.IllegalStateException: closed
        at okhttp3.internal.http.Http1xStream$ChunkedSource.read(Http1xStream.java:418)
        at okio.Buffer.writeAll(Buffer.java:993)
        at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:106)
        at okhttp3.ResponseBody.bytes(ResponseBody.java:128)
        at okhttp3.ResponseBody.string(ResponseBody.java:154)
        at hu.medev.projects.android.medev_bodybuilding.DB.Remote.APIRequest.doInBackground(APIRequest.java:39)
        at hu.medev.projects.android.medev_bodybuilding.DB.Remote.APIRequest.doInBackground(APIRequest.java:15)
        at android.os.AsyncTask$2.call(AsyncTask.java:288)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
        at java.lang.Thread.run(Thread.java:818) 

提前致谢, Tangomajom

0 个答案:

没有答案