okhttp|青训营笔记

114 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的第7天

okhttp

什么是OKHttp

在okHtt以前, 我们使用HttpURLConnection或者HttpClient.

  • HttpClient是Apache基金会的一个开源网络库, 功能十分强大, API数量众多, 但是正是由于庞大的API数量使得我们很难在不破坏兼容性的情况下对它进行升级和扩展, 所以Android团队在提升和优化HttpClient方面的工作态度并不积极.
  • HttpURLConnection是一种多用途, 轻量极的HTTP客户端, 提供的API比较简单, 可以容易地去使用和扩展. 不过在Android 2.2版本之前, HttpURLConnection一直存在着一些令人厌烦的bug. 比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。

所以OKhttp就解决了以上问题,仅具有高效的请求效率, 并且提供了很多开箱即用的网络疑难杂症解决方案.

okhttp 请求 首先我们要构造一个http请求,并查看请求具体内容 :

 final Request request = new Request.Builder().url("https://github.com/").build();
 
Response response = client.newCall(request).execute();

  • 所以一个类库要完成一个http请求, 需要包含 请求方法请求地址请求协议请求头请求体这五部分. 这些都在okhttp3.Request的类中有体现, 这个类正是代表http请求的类

相对,我们看下Okhttp库怎么表示一个响应:

image.png

可以看到Response类里面有Protocol代表请求协议, int code代表响应码, String message代表描述信息, Headers代表响应头, ResponseBody代表响应体. 当然除此之外, 还有Request代表持有的请求, Handshake代表SSL/TLS握手协议验证时的信息

HttpGET

  • 同步GET

同步GET的意思是一直等待http请求, 直到返回了响应. 在这之间会阻塞进程, 所以通过get不能在Android的主线程中执行, 否则会报错.

private final OkHttpClient client = new OkHttpClient();
 
public void run() throws Exception {
    Request request = new Request.Builder()
        .url("http://github.com")
        .build();
 
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
 
    Headers responseHeaders = response.headers();
    for (int i = 0; i < responseHeaders.size(); i++) {
      System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
    }
 
    System.out.println(response.body().string());
}
}

OkHttpClient实现了Call.Factory接口, Call负责发送执行请求和读取响应.
Request代表Http请求, 通过Request.Builder辅助类来构建.
client.newCall(request)通过传入一个http request, 返回一个Call调用. 然后执行execute()方法, 同步获得 Response代表Http请求的响应.
response.body()是ResponseBody类, 代表响应体, 可以通过responseBody.string()获得字符串的表达形式, 或responseBody.bytes()获得字节数组的表达形式, 这两种形式都会把文档加入到内存, 也可以通过responseBody.charStream()和responseBody.byteStream()返回流来处理

异步Get

  • 异步GET是指在另外的工作线程中执行http请求, 请求时不会阻塞当前的线程, 所以可以在Android主线程中使用

提取响应头

  • 当写请求头的时候, 使用header(name, value)可以设置唯一的name、value. 如果已经有值, 旧的将被移除, 然后添加新的. 使用addHeader(name, value)可以添加多值(添加, 不移除已有的).
  • 当读取响应头时, 使用header(name)返回最后出现的name、value. 通常情况这也是唯一的name、value. 如果没有值, 那么header(name)将返回null. 如果想读取字段对应的所有值, 使用headers(name)会返回一个list.
    为了获取所有的Header, Headers类支持按index访问.
private final OkHttpClient client = new OkHttpClient();
 
public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://api.github.com/repos/square/okhttp/issues")
        .header("User-Agent", "OkHttp Headers.java")
        .addHeader("Accept", "application/json; q=0.5")
        .addHeader("Accept", "application/vnd.github.v3+json")
        .build();
 
    Response response = client.newCall(request).execute();
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
 
    System.out.println("Server: " + response.header("Server"));
    System.out.println("Date: " + response.header("Date"));
    System.out.println("Vary: " + response.headers("Vary"));
}

使用Gson来解析JSON响应

  • Gson是一个在JSON和Java对象之间转换非常方便的api库. 这里我们用Gson来解析Github API的JSON响应.
private final OkHttpClient client = new OkHttpClient();
 private final Gson gson = new Gson();

 public void run() throws Exception {
   Request request = new Request.Builder()
       .url("https://api.github.com")
       .build();
   Response response = client.newCall(request).execute();
   if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

   Gist gist = gson.fromJson(response.body().charStream(), Gist.class);
   for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) {
     System.out.println(entry.getKey());
     System.out.println(entry.getValue().content);
   }
 }

 static class Gist {
   Map<String, GistFile> files;
 }

 static class GistFile {
   String content;
 }

响应缓存

  • 为了缓存响应, 你需要一个你可以读写的缓存目录, 和缓存大小的限制.
  • 一个缓存目录同时拥有多个缓存访问是错误的. 大多数程序只需要调用一次new OkHttp(), 在第一次调用时配置好缓存, 然后其他地方只需要调用这个实例就可以了. 否则两个缓存示例互相干扰, 破坏响应缓存, 而且有可能会导致程序崩溃.
  • 响应缓存使用HTTP头作为配置. 你可以在请求头中添加Cache-Control: max-stale=3600 , OkHttp缓存会支持.