OkHttp 是 Square 公司开源的一款网络框架,封装了一个高性能的 http
请求库。java
okhttp
来进行的okhttp
比较接近真正的 HTTP 协议的框架其余优势见:Android 网络框架比较(后面更新)
提及 okhttp 的介绍,介绍完这几个关键类就能够了!web
这个类主要是用来配置 okhttp
这个框架的,通俗一点讲就是这个类是管理这个框架的各类设置的。json
Call 类的工厂,经过 OkHttpClient 才能获得 Call 对象。api
OkHttpClient
应该被共享,使用 okhttp
这个框架的时候,最好要将 OkHttpClient
设置成单例模式,全部的 HTTP 在进行请求的时候都要使用这一个 Client
。由于每一个 OkHttpClient
都对应了本身的链接池和线程池。减小使用链接池和线程池能够减小延迟和内存的使用。相反的若是每一个请求都建立一个 OkHttpClient
的话会很浪费内存资源。缓存
OkHttpClient 有三个建立方法bash
第一个方法:直接使用 new OkHttpClient()
来建立一个实例对象就能够了,这个实例对象有默认的配置。默认请求链接超时时间 10 s ,读写超时时间 10 s,链接不成功会自动再次链接。服务器
第二个方法:就是经过 Builder
的方式来本身定义一个 OkHttpclient
。固然若是你直接 build
没有本身配置参数的话,效果和第一个方法是同样的。websocket
public final OkHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor())
.cache(new Cache(cacheDir,cacheSize))
.等等配置
.build();
复制代码
第三个方法:就是经过已有的 OkHttpClient
对象来复制一份共享线程池和其余资源的 OkHttpClient
对象。markdown
OkHttpClient agerClient = client.newBuilder()
.readTimeout(500,TimeUnit.MILLSECONS)
.build();
复制代码
这种方法的好处就是,当咱们有一个特殊的请求,有的配置有点不同,好比要求链接超过 1 s 就算超时,这个时候咱们就可使用这个方法来生成一个新的实例对象,不过他们共用不少其余的资源,不会对资源形成浪费。网络
关于 OkHttpClient 的配置改变都在 Builder 中进行
其实持有的线程池和链接池将会被自定释放若是他们保持闲置的话。
你也能够自动释放,释放后未来再调用 call 的时候会被拒接。
client.dispatcher().excurorService().shutdown()
清除链接池,注意清除后,链接池的守护线程可能会马上退出。
client.connectionPool().evictAll()
若是 Client 有缓存,能够关闭。注意:再次调用一个被关闭的 cache 会发生错误。也会形成 crash。
client.cache().close();
OkHttp 在 HTTP/2 链接的时候也会使用守护线程。他们闲置的时候将自动退出。
知道有这么一回事就行,通常不会主动调用。
Call 这个类就是用来发送 HTTP 请求和读取 HTTP 响应的一个类
这个类的方法不多,从上到下依次是:放弃请求、异步执行请求、同步执行请求。
这个类就是至关于 http
请求中的请求报文,是用来表达请求报文的,因此这里能够设置请求的 url、请求头、请求体等等和请求报文有关的内容。
主要方法罗列:
// 获取请求 url
public HttpUrl url();
// 获取请求方法类型
public String method();
// 获取请求头
public Headers headers();
//获取请求体
public RequestBody body();
// 获取 tag
public Object tag();
// 返回缓存控制指令,永远不会是 null ,即便响应不包含 Cache-Control 响应头
public CacheControl cacheControl();
// 是不是 https 请求
public boolean isHttps();
// Resquest{method=" ",url=" ",tag = " "}
public String toString();
复制代码
这是它的 Builder
中提供的方法,只设置 .url()
的时候默认是 post 请求。
介绍完请求报文就要介绍请求体了,这都是和 http
协议紧密联系的。
RequestBody 就是用来设置请求体的,它的主要方法就是下面这个几个静态方法,用来生成对应的请求体:
就是经过这几个方法来产生对应的不一样的请求体。MediaType 是用来描述请求体或者响应体类型的。好比请求体类型是 json
串格式的,那对应的 MediaType 就是MediaType.parse("application/json; charset=utf-8");
,若是上传的是文件那么对应的就是 application/octet-stream
,还有几个经常使用的类型 text/plain
imge/png
text/x-markdown
等等。
它还有两个子类:
FormBody 这个请求体是咱们平时最经常使用的,就是咱们平时使用 post
请求的时候,参数是键值对的形式。就是使用这个请求体最简单了。
说深一点,对应的请求报文是:
POST /test HTTP/1.1 请求行
Host: 32.106.24.148:8080 下面都是请求头
Content-Type: application/x-www-form-urlencoded 用于指明请求体的类型。
User-Agent: PostmanRuntime/7.15.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 954bda0d-dbc2-4193-addf-a7631cab2cfa,5ba2ebed-90b4-4f35-bcf5-80c4777de471
Host: 39.106.24.148:8080
accept-encoding: gzip, deflate
content-length: 133
Connection: keep-alive
cache-control: no-cache
key0=value0&key1=value1 请求体(也是咱们的参数)
复制代码
这是发送的原始的报文格式,用代码实现的话就是
// 建立客户端
OkHttpClient client = new OkHttpclient();
// 创建请求体
FormBody formBody = new FormBody.Builder()
.add("key0", "value0")
.add("key1","value1")
.build();
// 创建请求报文
Request request = new Request.Builder
.post(formBody)
.url("请求url")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("User-Agent", "PostmanRuntime/7.15.0")
.addHeader("Accept", "*/*")
.addHeader("Cache-Control", "no-cache")
.addHeader("Postman-Token", "954bda0d-dbc2-4193-addf-a7631cab2cfa,af7c027c-a7ba-4560-98ae-3a2a473ab88a")
.addHeader("Host", "39.106.24.148:8080")
.addHeader("accept-encoding", "gzip, deflate")
.addHeader("content-length", "133")
.addHeader("Connection", "keep-alive")
.addHeader("cache-control", "no-cache")
.build();
// 发起请求
client.newCall(request).excute();
复制代码
上面是使用了 FormBody
的形式,若是使用 RequestBody 的话就要更麻烦一些。
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "key0=value0&key1=value1");
Request request = new Request.Builder()
.url("http://39.106.24.148:8080/test")
.post(body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("User-Agent", "PostmanRuntime/7.15.0")
.addHeader("Accept", "*/*")
.addHeader("Cache-Control", "no-cache")
.addHeader("Postman-Token", "954bda0d-dbc2-4193-addf-a7631cab2cfa,af7c027c-a7ba-4560-98ae-3a2a473ab88a")
.addHeader("Host", "39.106.24.148:8080")
.addHeader("accept-encoding", "gzip, deflate")
.addHeader("content-length", "133")
.addHeader("Connection", "keep-alive")
.addHeader("cache-control", "no-cache")
.build();
Response response = client.newCall(request).execute();
复制代码
固然平时咱们使用的时候,不用拼上这么多的请求头,我这样写的目的就是为了更加还原请求报文。
还有一个子类 MultipartBody
这个能够用来构建比较复杂的请求体。
1995 年 Content-Type 的类型扩充了 multipart/form-data
用来支持向服务器发送二进制数据。若是一次提交多种类型的数据,好比:一张图片和一个文字,这个时候引入了 boundary
,boundary
使得 POST 能够知足这种提交多种不一样的数据类型。经过 boundary
能够实现多个不一样类型的数据同时存在在一个 Request 中。两个 boundary
之间就是一个类型的数据,而且能够从新设置 Content-Type
与 HTML 文件上传形式兼容。每块请求体都是一个请求体,能够定义本身的请求头。这些请求头能够用来描述这块请求。例如,他们的 Content-Disposition。若是 Content-Length 和 Content-Type 可用的话,他们会被自动添加到请求头中。
来看一下这种类型的请求报文是什么样的:
POST /web/UploadServlet HTTP/1.1
Content-Type: multipart/form-data; boundary=e1b05ca4-fc4e-4944-837d-cc32c43c853a
Content-Length: 66089
Host: localhost.tt.com:8080
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.5.0
–e1b05ca4-fc4e-4944-837d-cc32c43c853a
Content-Disposition: form-data; name=”file”; filename=”**.png”
Content-Type: image/png
Content-Length: 65744
fdPNG
IHDR�0B7M�iM�M�CCPIM�CC ProfileH��……………………IEND�B`�
–e1b05ca4-fc4e-4944-837d-cc32c43c853a
Content-Disposition: form-data; name=”comment”
Content-Length: 30
上传一个图
–e1b05ca4-fc4e-4944-837d-cc32c43c853a–
复制代码
第一个数据是一张 png 的图,从新设置了 Content-Type:image/png
中间的乱码就是图片的数据。这一堆数据前有一个空行,表示上下分别是请求头、请求体。
第二个数据,就是一个文本数据。
这样它们一块儿构成了请求体。
讲起来可能比较复杂,就记住,当既须要上传参数,又须要上传文件的时候用这种请求体。
MediaType mediaType = MediaType.parse("image/png");
RequestBody requestBody = new MultipartBody.Builder()
// 须要设置成表单形式不然没法上传键值对参数
.setType(MultipartBody.FORM)
.addPart(Headers.of("Content-Disposition", "form-data;name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data;name=\"imge\""),
RequestBody.create(mediaType, new File("路径/logo.png"))
).
build();
Request request = new Request.Builder()
.post(requestBody)
.url("https://api.imgur.com/3/image")
.build();
try {
mOkHttpClient.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
复制代码
简化写法:
MediaType mediaType = MediaType.parse("image/png");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("title","logo")
.addFormDataPart("img","logo.png",RequestBody.create(mediaType,new File("路径/logo.png")))
.build();
复制代码
Content-Disposition 能够用在消息体的子部分中,用来给出其对应字段的相关信息。做为 multipart body 中的消息头,第一个参数老是固定不变的 form-data; 附加的参数不区分大小写,而且拥有参数值,参数名与参数值用等号链接,参数之间用分号分隔。参数值用双引号括起来
// 好比这样,就是这种固定的格式
"Content-Disposition","form-data;name=\"mFile\";filename=\"xxx.mp4\""
复制代码
到这里关于请求的几个重要的类就讲完了。
只要掌握 http 请求的原理,使用起 okhttp 来也就不是什么问题了。
首先 OkHttpClient 是用来设置关于请求工具的一些参数的,好比超时时间、是否缓存等等。
Call 对象是发起 Http 请求的对象,经过 Call 对象来发起请求。
发起请求的时候,须要有请求报文,Request 对象就是对应的请求报文,能够添加对应的请求行、请求头、请求体。
提及请求体就是对应了 RequestBody 了。而后这个网络请求过程就完成了!