网络请求框架----okhttp3

本文详细介绍了OkHttp3的使用,包括添加依赖、基本用法如GET、POST请求,上传文件,自定义拦截器如日志和Header拦截器,以及如何扩展使用如下载进度、上传安全验证。此外,还探讨了HTTPS的信任所有证书和自定义证书配置。最后,深入解析了OkHttp3的源码,涉及初始化、网络请求执行流程、拦截器链和各个系统拦截器的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、okhttp3的使用

1、添加依赖

compile 'com.squareup.okhttp3:okhttp:3.7.0'
compile 'com.squareup.okio:okio:1.12.0'

2、基本用法

    (1)get异步请求

    private void  get(String url){
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        Request request = new Request.Builder()
                .url(url)
                .header("","")
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });
    }

(2)post异步请求(参数为Map)

    private void post(String url, Map<String, String> maps) {
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        if (maps == null) {
            maps = new HashMap<>();
        }
        Request.Builder builder = new Request.Builder()
                .url(url);
        if (maps != null && maps.size() > 0) {
            FormBody formBody = new FormBody.Builder();
            for (String key : maps.keySet()) {
                body.add(key, paramsMap.get(key));
            }
            builder.post(formBody.builder());
        }
        Request request = builder.build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });
    }

(3)post异步请求(参数为json)

private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");   
public void post(String url,JsonObject json) {
        
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url("")
                .post(body)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
            }
        });
    }

(4)上传文件  MutipartBody

 private void  postFile(){
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        RequestBody requestBody = 
  RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8") , new File(""));
        String name = "fileName";          //文件名称
        try {
            name = URLEncoder.encode(name, "UTF-8");                 //文件名称编码,防止出现中文乱码
        } catch (UnsupportedEncodingException e1) {
            //TODO
        }

        //定义请求体,前面三个为表单中的string类型参数,第四个为需要上传的文件
        MultipartBody mBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("fileSize" , "12123")
                .addFormDataPart("time" , "234234")
                .addFormDataPart("name" , name)
                .addFormDataPart("file" , name , requestBody)
                .build();
        
        Request request = new Request.Builder().url("").header("","").post(mBody).build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
            }
        });
    }

3、异步请求结果

call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //结果在工作线程中,不能直接更新UI
                //如果希望返回的是字符串
                final String responseData=response.body().string();
                //如果希望返回的是二进制字节数组
                byte[] responseBytes=response.body().bytes();
                //如果希望返回的是inputStream,有inputStream我们就可以通过IO的方式写文件.
                InputStream responseStream=response.body().byteStream();
 
            }
        });

注: 异步请求callback回调是在工作线程中,所以不能直接更新UI,可以通过Looper.myLooper()==Looper.getMainLooper()   进行简单判断,解决方式可以使用Handler

 

4、Request的参数RequestBody

    RequestBody是抽象类,FormBody和MultipartBody是其子类。

Request request = new Request.Builder()
                            .url("")
                            .header("", "")
                            .post(RequestBody   body)
                            .build();

 

//RequestBody的创建
RequestBody body = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=utf-8") , new File(""));
或
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
RequestBody imgBody = MultipartBody.create(MEDIA_TYPE_PNG, new Flie());

//FormBody的创建
FormBody body = new FormBody.Builder()
                .add("", "")
                .build();

//MultipartBody的创建
MultipartBody body=new MultipartBody.Builder()
                .addFormDataPart("key","value")
                .addFormDataPart("name","fileName",RequestBody body)
                .build();

5、自定义拦截器

(1)日志拦截器

public class LogInterceptor implements Interceptor {
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        Request request = chain.request();
        Headers headers = request.headers();
        Set<String> names = headers.names();
        Iterator<String> iterator = names.iterator();
        //打印请求路径
        Log.d(getClass().getSimpleName(), "url=" + request.url());
        //打印header
        Log.d(getClass().getSimpleName(), "=======headers   start=====");
        while (iterator.hasNext()) {
            String next = iterator.next();
            Log.d(getClass().getSimpleName(), next + ":" + headers.get(next));
        }
        Log.d(getClass().getSimpleName(), "=======headers   end=====");

        //打印post方式请求参数
        String method = request.method();
        if (method.equals("POST")) {
            RequestBody body = request.body();
            if (body != null) {
                if (body.contentType() != null) {
                    Log.d(getClass().getSimpleName(), "contentType:" + body.contentType().toString());
                }
                Log.d(getClass().getSimpleName(), "=======params   start=====");
                if (body instanceof FormBody) {
                    FormBody formBody = (FormBody) body;
                    for (int i = 0; i < formBody.size(); i++) {
                        Log.d(getClass().getSimpleName(), formBody.name(i) + ":" + formBody.value(i));
                    }
                }
                Log.d(getClass().getSimpleName(), "=======params   end=====");
            }

        }

        //打印response
        Response response = chain.proceed(request);
        ResponseBody body = response.body();
        if (body != null) {
            Log.d(getClass().getSimpleName(), "response:" + body.toString());
        }
        return response;
    }
}

(2)添加header拦截器

/*
 * 添加请求头
 */
public class HeadInterceptor implements Interceptor {
    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        Request request = chain.request();
        request = request.newBuilder()
                .addHeader("key", "value")
                .build();
        Headers headers = request.headers();
        Set<String> names = headers.names();
        Iterator<String> iterator = names.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            Log.d("aaa", next + ":" + headers.get(next));
        }
        Response response = chain.proceed(request);

        return response;
    }
}

6、用法扩展

(1)下载文件获取进度条

    OkHttpClient client = new OkHttpClient.Builder().build();
    okhttp3.Request request = new okhttp3.Request.Builder().url("").build();
    client.newCall(request).enqueue(new okhttp3.Callback() {
        @Override
        public void onFailure(okhttp3.Call call, IOException e) {
        }

        @Override
        public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
            InputStream is = null;
            byte[] buf = new byte[2048];
            int len = 0;
            FileOutputStream fos = null;
            try {
                is = response.body().byteStream();
                long total = response.body().contentLength();
                fos = new FileOutputStream("file");
                long sum = 0;
                while ((len = is.read(buf)) != -1) {
                    fos.write(buf, 0, len);
                    sum += len;
                    int progress = (int) (sum * 1.0f / total * 100);
                    //更新下载进度progress,这是在工作线程中
                }
                fos.flush();
                //下载成功
            } catch (Exception e) {
                //下载失败
            } finally {
                if (is != null) {
                    is.close();
                }
                if (fos != null) {
                    fos.close();
                }
            }
        }
    });

}

(2)上传进度

interface ProgressListener {
    void onProgress(long totalBytes, long remainingBytes, boolean done);
}
  

public RequestBody createCustomRequestBody(final MediaType contentType,final File file,final ProgressListener listener){
    return new RequestBody() {
        @Nullable
        @Override
        public MediaType contentType() {
            return contentType;
        }
        @Override
        public long contentLength() throws IOException {
            return file.length();
        }
        @Override
        public void writeTo(BufferedSink sink) throws IOException {
             Source source;
             try{
                 source= Okio.source(file);
                 Buffer buf=new Buffer();
                 Long remaining=contentLength();
                 for(long readCount;(readCount=source.read(buf,2048))!=-1;){
                     sink.write(buf,readCount);
                     listener.onProgress(contentLength(),remaining-=readCount,remaining==0);
                 }
             }catch (Exception e){
             }
        }
    };


OkHttpClient client = new OkHttpClient.Builder().build();
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("file", "fileName", createCustomRequestBody(MultipartBody.FORM, new File(""), new ProgressListener() {
    @Override
    public void onProgress(long totalBytes, long remainingBytes, boolean done) {

    }
}));
RequestBody requestBody=builder.build();
okhttp3.Request request = new okhttp3.Request.Builder().url("").post(requestBody).build();
client.newCall(request).enqueue(new okhttp3.Callback() {
    @Override
    public void onFailure(okhttp3.Call call, IOException e) {
    }

    @Override
    public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {

    }
});

(3)断点续传

 Request request = new Request.Builder()
                  .url("")
                  .header("RANGE", "bytes="+count)
                  .post(body)
                  .build();

(4)json解析

        //案例一
        JSONObject  object=new JSONObject();
        try {
            object.put("name","value");
            JSONArray array=new JSONArray();
            array.put("value1");
            array.put("value2");
            object.put("name1",array);
            object.toString();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        //案例二
        JSONObject   object1=new  JSONObject(new HashMap());
        
        //案例三
        try {
            JSONObject   object2=new  JSONObject("");
        } catch (JSONException e) {
            e.printStackTrace();
        }

(5)上传数据安全性验证

         第一步上传指定字段,标识所有参数的string

         第二步把第一步返回的字符串+token然后进行加密,上传到服务端

         第三步服务端验证

(6)response抽取

public interface BaseResponse{
    void onFailure(Request request, Throwable e);

    void onSuccess(JsonObject result);
}

 

call.enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                e.printStackTrace();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        cb.onFailure(request, e);
                    }
                });
            }

            @Override
            public void onResponse(final Response response) throws IOException {
                final String responseString = response.body().string();
                if (responseString.replaceAll("\\s", "").equals("{}")) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            cb.onFailure(response.request(), new Exception("response={}"));
                        }
                    });
                } else {
                    final JsonObject responseJson;
                    try {
                        responseJson = gson.fromJson(responseString, JsonElement.class).getAsJsonObject();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if (responseJson == null || responseJson.isJsonNull()) {
                                    cb.onFailure(response.request(), new Exception("response.isSuccessful():" + response.isSuccessful()));
                                    return;
                                }
                                try {
                                    String code = responseJson.get("code").getAsString();
                                    if ("1421".equals(code)) {//抽取特殊状态码
                                      
                                    }
                                    cb.onSuccess(responseJson);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                    cb.onFailure(response.request(), new Exception("Unknown Exception "));
                                }
                            }
                        });
                    } catch (JsonSyntaxException e) {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                cb.onFailure(response.request(), new Exception("Json Syntax Exception"));
                            }
                        });
                    }
                }
            }
        });

二、Https

 1、信任所有证书

 OkHttpClient.Builder okhttpClient = new OkHttpClient().newBuilder();
        //信任所有服务器地址
        okhttpClient.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                //设置为true
                return true;
            }
        });
        //创建管理器
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] x509Certificates,
                    String s) throws java.security.cert.CertificateException {
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return new java.security.cert.X509Certificate[] {};
            }
        } };
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            //为OkHttpClient设置sslSocketFactory
            okhttpClient.sslSocketFactory(sslContext.getSocketFactory());

        } catch (Exception e) {
            e.printStackTrace();
        }

        return okhttpClient.build();

2、自定义证书

/**
     * 自定义证书获取SSL
     */
    public static SSLContext sslContextForTrustedCertificates(InputStream... certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

                try {
                    if (certificate != null)
                        certificate.close();
                } catch (IOException e) {
                }
            }

            SSLContext sslContext = SSLContext.getInstance("TLS");

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());

            return sslContext;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }


     /**
     * 获取证书流
     */
    private static InputStream trustedCertificatesInputStream() {
        String certificateAuthority = "";
        return new Buffer()
                .writeUtf8(certificateAuthority)
                .inputStream();
    }


/**
*   设置
**/
 SSLContext sslContext = sslContextForTrustedCertificates(trustedCertificatesInputStream());
mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());

 

三、源码解析

1、Okhttp3初始化,源码如下:

 public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
  
  final Dispatcher dispatcher;//请求分发
  final Proxy proxy; 
  final List<Protocol> protocols;
  final List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors;    //用户自定义拦截器
  final List<Interceptor> networkInterceptors;    //网络拦截器
  final EventListener.Factory eventListenerFactory;
  final ProxySelector proxySelector;
  final CookieJar cookieJar;
  final Cache cache;
  final InternalCache internalCache;
  final SocketFactory socketFactory;
  final SSLSocketFactory sslSocketFactory;    //https证书
  final CertificateChainCleaner certificateChainCleaner;
  final HostnameVerifier hostnameVerifier;
  final CertificatePinner certificatePinner;
  final Authenticator proxyAuthenticator;
  final Authenticator authenticator;
  final ConnectionPool connectionPool;   //连接池
  final Dns dns;
  final boolean followSslRedirects;
  final boolean followRedirects;
  final boolean retryOnConnectionFailure;
  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
  final int pingInterval;

使用builder设计模式初始化OkHttpClient实例,在构造函数中创建了成员变量dispatcher(负责网络请求分发),dispatcher中包含三个成员变量:同步正在执行队列runningSyncCalls,泛型为RealCall;异步正在执行队列runningAsyncCalls,泛型为AsyncCall,长度为64;异步等待队列 readyAsyncCalls,泛型为AsyncCall;源码如下:

public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;
  private Runnable idleCallback;

  /** Executes calls. Created lazily. */
  private ExecutorService executorService;

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }

先看一下AsyncCall类, 它是ReayCall的内部类,继承了抽象类NamedRunnable,覆写抽象方法execute(),而NamedRunnable类实现了Runnable接口,因此AsyncCall是Runnable的子类,是多线程类。源码如下:

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @Override    
    protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }





public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override 
  public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

2、client.newCall(request)实际上返回的是一个RealCall的实例,RealCall实现了Call接口。RealCall的构造函数是OkHttpClient的实例引用和Request的实例引用,所以RealCall的实例分别持有了okhttpClient和ruquest的引用,源码如下:

 /**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
 ------------参数为OkHttpClient和request--------
    return new RealCall(this, request, false /* for web socket */);
  }

RealCall中提供了两个重要的方法,execute()和enqueue(),其中execute是同步执行方法,enqueue是异步请求。源码如下:

final class RealCall implements Call {
  final OkHttpClient client;
  final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
  final EventListener eventListener;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  final boolean forWebSocket;

  // Guarded by this.
  private boolean executed;

  RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();

    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

    // TODO(jwilson): this is unsafe publication and not threadsafe.
    this.eventListener = eventListenerFactory.create(this);
  }

  @Override 
  public Request request() {
    return originalRequest;
  }

---------同步请求-----------------------
  @Override 
  public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }

  private void captureCallStackTrace() {
    Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
    retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
  }

-----------------异步请求----------------
  @Override 
  public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

  @Override 
  public void cancel() {
    retryAndFollowUpInterceptor.cancel();
  }

  @Override 
  public synchronized boolean isExecuted() {
    return executed;
  }

  @Override 
  public boolean isCanceled() {
    return retryAndFollowUpInterceptor.isCanceled();
  }

  @SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
  @Override 
  public RealCall clone() {
    return new RealCall(client, originalRequest, forWebSocket);
  }

  StreamAllocation streamAllocation() {
    return retryAndFollowUpInterceptor.streamAllocation();
  }

 
  /**
   * Returns a string that describes this call. Doesn't include a full URL as that might contain
   * sensitive information.
   */
  String toLoggableString() {
    return (isCanceled() ? "canceled " : "")
        + (forWebSocket ? "web socket" : "call")
        + " to " + redactedUrl();
  }

  String redactedUrl() {
    return originalRequest.url().redact();
  }

  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }
}

3、主要看异步请求方法enqueue();首先把callback封装成AsyncCall类,这是个多线程类,然后调用dispatcher.enqueue方法,源码如下:

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

 在dispatcher.enqueue(AsyncCall  call)方法中,先判断异步正在执行队列是否满了(最多64个),如果满了就添加到异步等待队列中;反之则创建了一个线程池,把这个新任务添加到线程池中。等待这个任务能执行的时候,自会执行自己的execute方法(AsyncCall的execute方法)。下面是源码以及线程池的创建源码:

 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }


---------线程池的创建核心线程数为0,最大线程数是int的最大值-------------------------------------
 public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

最后看AsyncCall类的execute()方法,在try中调用getResponseWithInteceptorChain()真正的网络请求,在catch中返回错误,在finally中调用dispatcher的finished(AsyncCall)进行扫尾工作。源码如下:

@Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }

我们先看看扫尾工作finished方法,把这个任务从正在执行的异步队列中移除,如果等待队列不为空,则从等待队列中取出一个任务添加到正在执行的异步队列中,并运行新的任务,源码如下:

void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }

/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
    finished(runningSyncCalls, call, false);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
}


private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
}

4、重中之重,getResponseWithInterceptorChain()返回的就是数据Response,它采用了责任链设计模式。在该方法中,首先创建拦截器集合,把用户自定义的拦截器和系统添提供的拦截器都添加到这个集合中,然后封装成RealInterceptorChian链,然后调用proceed()方法,参数为request,把结果返回。源码如下:

Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(
        interceptors, null, null, null, 0, originalRequest);
    return chain.proceed(originalRequest);
  }

RealInterceptorChain类实现了接口Interceptor.Chain,需要实现proceed方法 ,源码如下:

public final class RealInterceptorChain implements Interceptor.Chain {
  private final List<Interceptor> interceptors;
  private final StreamAllocation streamAllocation;
  private final HttpCodec httpCodec;
  private final RealConnection connection;
  private final int index;
  private final Request request;
  private int calls;

  public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, RealConnection connection, int index, Request request) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
  }

  @Override public Connection connection() {
    return connection;
  }

  public StreamAllocation streamAllocation() {
    return streamAllocation;
  }

  public HttpCodec httpStream() {
    return httpCodec;
  }

  @Override public Request request() {
    return request;
  }

  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  }

  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    return response;
  }
}

在proceed方法中,取出一个拦截器,调用interceptor.intercept(next),next是新封装的拦截器链RealInterceptorChain,每个拦截器是实现了Interceptor接口,实现intercept方法,在该方法中,可以对ruquest进行再次操作,然后调用chain.proceed(request)那会结果,然后再多response进行操作,然后返回给上一级拦截器interceptor,例:BridgeInterceptor的源码:

@Override public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();

    RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

    --------获取提交数据的长度-------
      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
    --------添加请求头-------------
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }
    }

    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }

    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }

    Response networkResponse = chain.proceed(requestBuilder.build());

    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
  }

5、系统提供的拦截器

  • RetryAndFollowUpInterceptor

           处理重试的一个拦截器,里面是一个死循环,它会去尝试处理一些异常,只要不是指致命的异常就会重新发起一次请求,

如果是致命的异常(arouter,io异常)就会抛出来,停止死循环;还会处理一些重定向问题(307)

 @Override public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();

    streamAllocation = new StreamAllocation(
        client.connectionPool(), createAddress(request.url()), callStackTrace);

    int followUpCount = 0;
    Response priorResponse = null;
    while (true) {
      if (canceled) {
        streamAllocation.release();
        throw new IOException("Canceled");
      }

      Response response = null;
      boolean releaseConnection = true;
      try {
        response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null);
        releaseConnection = false;
      } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;
        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      } finally {
        // We're throwing an unchecked exception. Release any resources.
        if (releaseConnection) {
          streamAllocation.streamFailed(null);
          streamAllocation.release();
        }
      }

      // Attach the prior response if it exists. Such responses never have a body.
      if (priorResponse != null) {
        response = response.newBuilder()
            .priorResponse(priorResponse.newBuilder()
                    .body(null)
                    .build())
            .build();
      }

      Request followUp = followUpRequest(response);

      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }

      closeQuietly(response.body());

      if (++followUpCount > MAX_FOLLOW_UPS) {
        streamAllocation.release();
        throw new ProtocolException("Too many follow-up requests: " + followUpCount);
      }

      if (followUp.body() instanceof UnrepeatableRequestBody) {
        streamAllocation.release();
        throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
      }

      if (!sameConnection(response, followUp.url())) {
        streamAllocation.release();
        streamAllocation = new StreamAllocation(
            client.connectionPool(), createAddress(followUp.url()), callStackTrace);
      } else if (streamAllocation.codec() != null) {
        throw new IllegalStateException("Closing the body of " + response
            + " didn't close its backing stream. Bad interceptor?");
      }

      request = followUp;
      priorResponse = response;
    }
  }
  • BridgeInterceptor

    设置通用的请求头:Connect-type  Connection  Content-length   Cookie

    返回的处理,如果返回的数据被压缩了采用AipSource,保存Cookie

@Override public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.request();
    Request.Builder requestBuilder = userRequest.newBuilder();

    RequestBody body = userRequest.body();
    if (body != null) {
      MediaType contentType = body.contentType();
      if (contentType != null) {
        requestBuilder.header("Content-Type", contentType.toString());
      }

      long contentLength = body.contentLength();
      if (contentLength != -1) {
        requestBuilder.header("Content-Length", Long.toString(contentLength));
        requestBuilder.removeHeader("Transfer-Encoding");
      } else {
        requestBuilder.header("Transfer-Encoding", "chunked");
        requestBuilder.removeHeader("Content-Length");
      }
    }

    if (userRequest.header("Host") == null) {
      requestBuilder.header("Host", hostHeader(userRequest.url(), false));
    }

    if (userRequest.header("Connection") == null) {
      requestBuilder.header("Connection", "Keep-Alive");
    }

    // If we add an "Accept-Encoding: gzip" header field we're responsible for also decompressing
    // the transfer stream.
    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null && userRequest.header("Range") == null) {
      transparentGzip = true;
      requestBuilder.header("Accept-Encoding", "gzip");
    }

    List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
      requestBuilder.header("Cookie", cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
      requestBuilder.header("User-Agent", Version.userAgent());
    }

    Response networkResponse = chain.proceed(requestBuilder.build());

    HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());

    Response.Builder responseBuilder = networkResponse.newBuilder()
        .request(userRequest);

    if (transparentGzip
        && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
        && HttpHeaders.hasBody(networkResponse)) {
      GzipSource responseBody = new GzipSource(networkResponse.body().source());
      Headers strippedHeaders = networkResponse.headers().newBuilder()
          .removeAll("Content-Encoding")
          .removeAll("Content-Length")
          .build();
      responseBuilder.headers(strippedHeaders);
      responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
  }

    6.3、CacheInterceptor

    6.4、ConnectInterceptor

    6.5、CallServerInterceptor

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值