OKHttp 4.x 入门手册
在日常的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()); } });