前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >okhttp 使用笔记

okhttp 使用笔记

作者头像
艳龙
发布2021-12-16 17:34:26
4710
发布2021-12-16 17:34:26
举报
文章被收录于专栏:yanlongli_艳龙yanlongli_艳龙

前言

okhttp是一个网络请求框架,也是目前市面上使用最多的网络框架之一。 之前参与的项目一直没使用,这次刚好有个机会使用OKHttp,记录下。

使用笔记

okhttp git地址: https://github.com/square/okhttp okhttp 相关文档介绍:https://square.github.io/okhttp/https/

okhttp 使用如果没有特殊需求,使用相对简单,如下:

1. Get a URL
代码语言:javascript
复制
OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  try (Response response = client.newCall(request).execute()) {
    return response.body().string();
  }
}
2. Post to a Server
代码语言:javascript
复制
public static final MediaType JSON
    = MediaType.get("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(json, JSON);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  try (Response response = client.newCall(request).execute()) {
    return response.body().string();
  }
}

okhttp 使用大体步骤可以分为以下3步:

  1. 创建一个 OkHttp 的实例例
  2. 创建 Request
  3. 创建 Call 并发起⽹网络请求 tips: execute() 为同步方法, Android中常用的enqueue()在异步线程发起网络请求

源码分析

OkHttpClient 包含整个网络请求的配置,配置信息如下:

代码语言:javascript
复制
    static final List<Protocol> DEFAULT_PROTOCOLS;
    static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS;
    final Dispatcher dispatcher;  // 任务分发类,用于调度后台发起的⽹网络请求,控制线程的分发和性能平衡(有后台总请求数和 单主机总请求数的控制)
    @Nullable
    final Proxy proxy;            // 代理设置
    final List<Protocol> protocols;   // ⽀持的应⽤层协议,例如: HTTP/1.1、HTTP/2 等
    final List<ConnectionSpec> connectionSpecs;   //应用层支持的 Socket 设置,使⽤明文传输(⽤于 HTTP)还是某个版本的 TLS(用于 HTTPS)
    final List<Interceptor> interceptors;
    final List<Interceptor> networkInterceptors;
    final okhttp3.EventListener.Factory eventListenerFactory;
    final ProxySelector proxySelector;
    final CookieJar cookieJar;
    @Nullable
    final Cache cache;
    @Nullable
    final InternalCache internalCache;
    final SocketFactory socketFactory;
    @Nullable
    final SSLSocketFactory sslSocketFactory;
    @Nullable
    final CertificateChainCleaner certificateChainCleaner;
    final HostnameVerifier hostnameVerifier;  // 用于验证 HTTPS 握手过程中下载到的证书所属者是否和⾃己要访问的主机名⼀致
    final CertificatePinner certificatePinner; // HTTPS校验时,通过验证证书公钥来判断连接是否可用
    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;

newCall(Request): 是发起网络请求的入口函数。返回一个RealCall对象,它是 Call接⼝的实现. 当调用enqueue() 方法时, 会调用Dispatcher分配到线程中,把请求放到后台

enqueue(Callback) : 是RealCall中的函数。 Android 常用enqueue(Callback)来发起异步的网络请求。 异步请求最后会调用AsyncCall 中的execute()

代码语言:javascript
复制
    protected void execute() {
            boolean var1 = false;

            try {
                Response var2 = RealCall.this.getResponseWithInterceptorChain();
                if (RealCall.this.retryAndFollowUpInterceptor.isCanceled()) {
                    var1 = true;
                    this.responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
                } else {
                    var1 = true;
                    this.responseCallback.onResponse(RealCall.this, var2);
                }
            } catch (IOException var6) {
                if (var1) {
                    Platform.get().log(4, "Callback failure for " + RealCall.this.toLoggableString(), var6);
                } else {
                    RealCall.this.eventListener.callFailed(RealCall.this, var6);
                    this.responseCallback.onFailure(RealCall.this, var6);
                }
            } finally {
                RealCall.this.client.dispatcher().finished(this);
            }
        }

 //getResponseWithInterceptorChain 
//  把所有配置好的 Interceptor 放在 ⼀个 List 中,然后作为参数,创建一个 RealInterceptorChain 对象,并调⽤用 chain.proceed(request) 来发起请求和获取响应

okhttp实现https请求

参考连接:https://square.github.io/okhttp/https/

HTTPS是包含了HTTP协议及SSL /TLS协议这两部分内容,简单的理解就是基于SSL/TLS进行HTTP的加密传输。 所以https请求会有证书相关的验证。

1. 使用CA颁发的证书

okhttp默认情况下是支持https协议的网站的,例如https://www.baidu.com

2. 使用自签名证书

需要自己处理证书校验。( 可以选择信任所有证书 或者 自定义证书校验 )

a. 信任所有证书(处理比较粗暴,忽略安全问题,不建议使用)

处理方式可以google查询。有很多介绍

b. 证书校验

固定证书校验:

代码语言:javascript
复制
  private final OkHttpClient client = new OkHttpClient.Builder()
      .certificatePinner(
          new CertificatePinner.Builder()
              .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
              .build())
      .build();

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://publicobject.com/robots.txt")
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      for (Certificate certificate : response.handshake().peerCertificates()) {
        System.out.println(CertificatePinner.pin(certificate));
      }
    }
  }

自定义证书校验

代码语言:javascript
复制
private final OkHttpClient client;

  public CustomTrust() {
    X509TrustManager trustManager;
    SSLSocketFactory sslSocketFactory;
    try {
      trustManager = trustManagerForCertificates(trustedCertificatesInputStream());
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(null, new TrustManager[] { trustManager }, null);
      sslSocketFactory = sslContext.getSocketFactory();
    } catch (GeneralSecurityException e) {
      throw new RuntimeException(e);
    }

    client = new OkHttpClient.Builder()
        .sslSocketFactory(sslSocketFactory, trustManager)
        .build();
  }

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://publicobject.com/helloworld.txt")
        .build();

    Response response = client.newCall(request).execute();
    System.out.println(response.body().string());
  }

  private InputStream trustedCertificatesInputStream() {
    ... // Full source omitted. See sample.
  }

  public SSLContext sslContextForTrustedCertificates(InputStream in) {
    ... // Full source omitted. See sample.
  }

域名校验

代码语言:javascript
复制
/**
     * 实现HostnameVerifier接口
     */
    public class TrustAllHostnameVerifier implements HostnameVerifier {

        @Override
        public boolean verify(String hostname, SSLSession session) {
            // demo是信任素有证书,可根据具校验修改
            return true;
        }
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/2/8 下午,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 使用笔记
    • 1. Get a URL
      • 2. Post to a Server
      • 源码分析
      • okhttp实现https请求
        • 1. 使用CA颁发的证书
          • 2. 使用自签名证书
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档