OKHttp 4.x 入门手册

发布于 2020-02-24  4,182 次阅读


在日常的web开发中,我们经常会遇到调用外部接口的情况,针对一个普通的java项目,我们可能会使用apache的httpclient实现,不过这个组件效率可能比较低下,android在6.0的时候就放弃使用这个组件了。
我看了一下自己正在的开发项目,HttpUtil中网络请求是通过HttpsURLConnection实现的,这东西是没有连接池的,并发性能是不存在的。想来想去干脆改成okhttp算了。


1.POM文件添加相关依赖
使用okhttp只需要添加一个依赖即可,注意okhttp从4.0版本开始从java平台迁移到kt平台了。不懂kt的话,源码阅读起来可能有点头疼。

    <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.4.0</version>
    </dependency>

2.编写一个简单的http post请求封装
这串代码是从官方Github上抄下来的。我们可以看到代码很清晰,

// 定义一个MediaType,标识请求数据的类型 这个是必须的,不过okhttp似乎没有对应的枚举类,这个字符串要手写
public static final MediaType JSON
    = MediaType.get("application/json; charset=utf-8");
// 创建client对象 创建调用的工厂类 具备了访问http的能力
OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  //  创建请求的请求体
  RequestBody body = RequestBody.create(json, JSON);
  // 创建request
  Request request = new Request.Builder()
      .url(url)
       // get请求
       //.get()
       // post请求
      .post(body)
      .build();
   // 创建一个通信请求
  try (Response response = client.newCall(request).execute()) {
    // 尝试将返回值转换成字符串并返回
    return response.body().string();
  }
}

3.代码解析
从上面的代码我们可以看到几个关键的类:
MediaType OkHttpClient RequestBody Request Call Response

[infobox title="MediaType"]
这东西指的是http请求中的header的Content-Type。
MediaType无法实例化(私有构造函数)
使用内部定义的静态方法parse(media_type_str)来创建实例
[/infobox]
[infobox title="OkHttpClient"]
这是一个工厂类,创建请求实例(Call)用的,这个类可以直接new出来(参数全部使用默认值),也可以用builder模式自带参数,比如

// 设置30s超时,并使用本地代理访问请求
OkHttpClient client = 
    new OkHttpClient.Builder()
    .callTimeout(30, TimeUnit.SECONDS)
    .proxy(new Proxy(Proxy.Type.HTTP, 
        new InetSocketAddress("127.0.0.1", 1080)))
    .build();

一般OkHttpClient是单例的(工厂总不会有多个实例吧?)
[/infobox]
OkHttpClient中有个方法newCall(request)方法,这是构建网络请求的工厂方法,返回一个Call接口实例,每个Call实例代表了一个已构建好的请求,可以被取消,但不能被调用多次。
Call接口中有一个execute方法,是一个同步请求方法,发起网络请求时会阻塞线程。

[infobox title="RequestBody"]
请求体,不能new出来,使用静态方法RequestBody.create构建,create方法第一个参数是MediaType,第二个参数可以是个字符串json,一个File,字节数组。
当然也可以由FormBody构建一个表单请求体,示例如下

RequestBody requestBody = new FormBody.Builder()
        .add("search", "Jurassic Park")
        .build();

[/infobox]
[infobox title="Call"]
实现类是RealCall,newcall方法使用调用的是RealCall类。
只能执行和读取一次。
[/infobox]
[infobox title="Response"]
包装后的请求返回结果
body()方法返回一个ResponseBody,header(String name)方法可以获取响应头。code()方法返回响应码。
ResponseBody就是body,可以拿到字符串或者字节数组或者换成一个流。
[/infobox]
4.异步请求
call.execute()方法是同步的,如果想要实现异步请求,那么需要做一点修改,改成调用call的enqueue方法,传入一个Callback接口实现类。
Callback定义了2个方法,一个是请求错误的事件(指的是网络请求错误,给出的也是IO异常),一个是请求成功的事件。

 new OkHttpClient.Builder().build().newCall(
         new Request.Builder()
                 .url(fuhaoProperties.getUrl())
                 .post(RequestBody.create(json, createMediaType))
                 .addHeader("x-fhld-access-key-id", fuhaoProperties.getAccessKeyId())
                 .addHeader("x-fhld-signature", signature)
                 .build()).enqueue(new Callback() {
     @Override
     public void onFailure(@NotNull Call call, @NotNull IOException e) {
         Log.d(TAG, "onFailure: ");
     }

     @Override
     public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
         Log.d(TAG, "onResponse: " + response.body().string());
     }
 });
届ける言葉を今は育ててる
最后更新于 2020-02-24