OkHttp使用及流程分析

  1. get & post
    1.1 组装Get or Post请求
    Request requestGet = new Request.Builder().url(url).build();
    // 其他request可选项
    //.tag(tag)
    //.header(key, value)
    //.cacheControl(CacheControl.FORCE_NETWORK)
    //.method(METHOD_GET, null)
    Request requestPost = new Request.Builder().url(url).post(requestBody).build(); RequestBody: FormBody formBody = new FormBody.Builder().add(key, value).build(); // 提交表单,使用默认MediaType application/x-www-form-urlencoded RequestBody fileBody = RequestBody.create(MediaType.parse(""), file); // 提交文件(上传文件) RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json.toString); // 提交Json MultipartBody.Builder.setType(MultipartBody.FORM).addPart(key, value).addPart(fileBody).build(); // 提交表单和文件

    1.2 发送请求
    Call call = new OkHttpClient.Builder().build().newCall(request);
    非Async方式:
    Response response = call.execute();
    Async方式:
    call.enqueue(new Callback() {
    onFailure(Call call, IOException e){非UI线程}
    onResponse(Call call, Response response){非UI线程}
    });
  2. 下载文件 & 图片显示
    同1中的使用方式,组装请求后发送,拿到Response或者在Callback中对Response做进一步处理。
    ResponseBody body = Response.body();
    InputStream is = body.byteStream(); // 获取response的InputStream流,这个用于直接read然后保存在文件(下载)或者Bitmap中。
    byte[] bytes = body.bytes(); // 获取response的byte数据
    Reader reader = body.charStream();
    String string = body.string();
  3. 取消
    Call call; call.cancel();
    对于同一个OkHttpClient中的Call,可以在dispatcher中进行遍历查询。
    for (Call call: client.dispatcher().queuedCalls()) {
    if (call.request().tag() == TAG) {} // 根据tag判断
    if (call.request().url() == URL){} // 根据url判断
    if (call.request().header(key) == VALUE){} // 根据header判断
    }
    for (Call call: client.dispatcher().runningCalls())
    client.dispatcher().cancelAll(); // 取消全部
  4. 【OkHttp使用及流程分析】OkHttpClient的设置(OkHttpClient.Builder)
    public Builder() {
    dispatcher = new Dispatcher();
    protocols = DEFAULT_PROTOCOLS;
    connectionSpecs = DEFAULT_CONNECTION_SPECS;
    eventListenerFactory = EventListener.factory(EventListener.NONE);
    proxySelector = ProxySelector.getDefault();
    cookieJar = CookieJar.NO_COOKIES;
    socketFactory = SocketFactory.getDefault();
    hostnameVerifier = OkHostnameVerifier.INSTANCE;
    certificatePinner = CertificatePinner.DEFAULT;
    proxyAuthenticator = Authenticator.NONE;
    authenticator = Authenticator.NONE;
    connectionPool = new ConnectionPool();
    dns = Dns.SYSTEM;
    followSslRedirects = true;
    followRedirects = true;
    retryOnConnectionFailure = true;
    connectTimeout = 10_000;
    readTimeout = 10_000;
    writeTimeout = 10_000;
    pingInterval = 0;
    }
    @Nullable Proxy proxy;
    final List interceptors = new ArrayList<>();
    final List networkInterceptors = new ArrayList<>();
    @Nullable Cache cache;
    @Nullable InternalCache internalCache;
    @Nullable SSLSocketFactory sslSocketFactory;
    @Nullable CertificateChainCleaner certificateChainCleaner;
  5. Call的执行流程
    5.1 RealCall
    创建RealCall并执行RealCall中的execute或enqueue方法
    class RealCall {
    final OkHttpClient client;
    final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
    Response execute() { try { client.dispatcher().executed(this); // dispatcher.runningSyncCalls.add(call); ArrayDeque来保存runningCalls Response result = getResponseWithInterceptorChain(); if (result == null) throw new IOException("Canceled"); return result; } finally { client.dispatcher().finished(this); } }void enqueue(Callback callback) { client.dispatcher().enqueue(new AsyncCall(responseCallback)); // dispatcher.runningAsyncCalls.add(call); ArrayDeque来保存runningCalls。 //dispatcher中使用ExecutorService维护了一个线程池,来执行Runnable }class AsyncCall extends NamedRunnable { void execute() { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { responseCallback.onResponse(RealCall.this, response); } } }Response getResponseWithInterceptorChain() { List 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); } }

    5.2 RealInterceptorChain & Interceptor
    index = 0
    Response proceed(Request) {
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
    }
    (client.interceptors) index = 1 // This interceptor recovers from failures and follows redirects as necessary.负责失败重试及重定向 RetryAndFollowUpInterceptor.intercept(Chain chain) { Response priorResponse = null; while (true) { // 调用Chain的proceed,调用下一个Interceptor response = ((RealInterceptorChain) chain).proceed(request, streamAllocation, null, null); // RouteException, IOException 等不再重试,throw exceptionsif (priorResponse != null) { // Attach the prior response if it exists. Such responses never have a body. response = response.newBuilder() .priorResponse(priorResponse.newBuilder() .body(null) .build()) .build(); }Request followUp = followUpRequest(response); // 拿到新的Request(重定向或重试)if (followUp == null) { // 没有新的request了,返回response return response; }if (!sameConnection(response, followUp.url())) { // 如果重定向了,使用新的StreamAllocation streamAllocation.release(); streamAllocation = new StreamAllocation(client.connectionPool(), createAddress(followUp.url()), callStackTrace); }request = followUp; priorResponse = response; // 保存此次的Response为prior, 保存followUp作为新的request,进入循环 }}index = 2 // Bridges from application code to network code. First it builds a network request from a user // request. Then it proceeds to call the network. Finally it builds a user response from the network // response. // 负责把用户构造的请求转换为发送到服务器的请求,把服务器端返回的响应转换为用户友好的响应。 BridgeInterceptor.intercept(Chain chain) { // request转换 Request userRequest = chain.request(); Request.Builder requestBuilder = userRequest.newBuilder(); RequestBody body = userRequest.body(); // add or remove Header(根据原request参数判断是否增加) requestBuilder.header("Content-Type", contentType.toString()); requestBuilder.header("Content-Length", Long.toString(contentLength)); requestBuilder.removeHeader("Transfer-Encoding"); requestBuilder.header("Host", hostHeader(userRequest.url(), false)); requestBuilder.header("Connection", "Keep-Alive"); requestBuilder.header("Accept-Encoding", "gzip"); // requestBuilder.header("Cookie", cookieHeader(cookies)); requestBuilder.header("User-Agent", Version.userAgent()); // 转换request完毕,使用新的request继续执行 Response networkResponse = chain.proceed(requestBuilder.build()); // response转换 HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers()); // 更新cookieResponse.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))); }// 返回转换后的新response return responseBuilder.build(); index = 3 // Serves requests from the cache and writes responses to the cache. // 从cache取request,将Response保存到cache CacheInterceptor.intercept(Chain chain) { // 先调用Cache,拿到Response Response cacheCandidate = cache != null ? cache.get(chain.request()) : null; // 根据Cache策略判断能否使用cache,能否使用network // 如果不能使用network,则返回cacheResponse或者错误response// 调用网络 Response networkResponse = chain.proceed(networkRequest); // 如果有CacheResponse,根据条件决定返回 if (cacheResponse != null) { if (networkResponse.code() == HTTP_NOT_MODIFIED) { // 返回CacheResponse } }// 使用networkResponse Response response = networkResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); // 如果支持Cache,保存Response到Cache cacheWritingResponse(cacheRequest, response); }index = 4 // Opens a connection to the target server. 创建一个到Server端的Connection,HttpCodec,然后传到下一个拦截器 ConnectInterceptor.intercept(Chain chain) { RealInterceptorChain realChain = (RealInterceptorChain) chain; Request request = realChain.request(); StreamAllocation streamAllocation = realChain.streamAllocation(); // We need the network to satisfy this request. Possibly for validating a conditional GET. boolean doExtensiveHealthChecks = !request.method().equals("GET"); HttpCodec httpCodec = streamAllocation.newStream(client, doExtensiveHealthChecks); RealConnection connection = streamAllocation.connection(); return realChain.proceed(request, streamAllocation, httpCodec, connection); }(client.networkInterceptors) index = 5 // This is the last interceptor in the chain. It makes a network call to the server.这个最后一个拦截器,负责真正和server端交互。 CallServerInterceptor.intercept(Chain chain) { ... Response response = responseBuilder .request(request) .handshake(streamAllocation.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); ... }

  6. 项目地址
    https://github.com/guolina02/HttpDemo

    推荐阅读