从http协议角度分析okhttp
Okhttp简介
OkHttp是Square公司开发的开源网络框架,封装了高性能的http
请求库。
- 支持spdy、http2.0、websocket等协议
- 支持同步和异步请求
- 封装线程池和数据转换,提高性能。
- Android 6.0自带的网络请求API底层是使用
okhttp
实现的
- 使用更接近真实HTTP协议框架的
okhttp
其他优点请参见:Android网络框架对比(稍后更新)
说到okhttp的介绍,就介绍这几个关键类吧!
Okhttp中几个重要的类介绍
OkHttpClient
该类主要用于配置okhttp
框架。通俗地说,这个类管理这个框架的各种设置。
Call类工厂,可以通过OkHttpClient获取Call对象。
OkHttpClient使用注意事项
OkHttpClient
应该共享。使用okhttp
这个框架时,最好将OkHttpClient
设置为单例模式。所有的HTTP请求都是要使用这个Client
。因为每个OkHttpClient
都对应着自己的连接池和线程池。减少连接池和线程池的使用可以减少延迟和内存使用。相反,如果每个请求都创建一个OkHttpClient
,就会造成内存资源的浪费。
创建OkHttpClient
OkHttpClient共有三种创建方法
第一种方法:只需使用new OkHttpClient()
创建实例对象即可。该实例对象具有默认配置。默认请求连接超时时间为10秒,读写超时时间为10秒。如果连接不成功,会自动重新连接。
第二种方法是通过Builder
定义一个OkHttpclient
。当然,如果你直接build
而不自己配置参数的话,效果会和第一种方法一样。
public 最终 OkHttpClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor())
.cache(新缓存(cacheDir,cacheSize))
.等待配置
.build();
第三种方法:使用已有的OkHttpClient
对象复制一个共享线程池等资源的OkHttpClient
对象。
OkHttpClient agerClient = client.newBuilder()
.readTimeout(500,TimeUnit.MILLSECONS)
.build();
这种方法的好处是,当我们有特殊要求,有些配置有点不同的时候,比如连接需要超过1s,就会超时。这时候我们就可以使用这个方法来生成一个新的实例对象。然而,他们共享许多其他资源,不会浪费资源。
OkHttpClient的配置变更全部在Builder中进行
如果不再需要可以关闭它
事实上,持有的线程池和连接池如果空闲的话会自动释放。
也可以自动释放。释放后,以后调用将被拒绝。
client.dispatcher().excurorService().shutdown()
清除连接池。注意,清除后,连接池的守护线程可能会立即退出。
client.connectionPool().evictAll()
如果客户端有缓存,可以关闭。注意:再次调用关闭的缓存会导致错误。它还会导致崩溃。
client.cache().close();
OkHttp 在连接到 HTTP/2 时也使用守护线程。空闲时它们会自动退出。
只要知道有这么个东西,一般都不会主动去调用。
拨打班级
Call 该类是用于发送HTTP请求和读取HTTP响应的类
这个类的方法很少。从上到下分别是:放弃请求、异步执行请求、同步执行请求。
请求课程
该类相当于http
request中的请求消息,用于表达请求消息,所以这里可以设置请求url、请求头、请求体等以及请求消息相关内容。
主要方法列举:
//获取请求url
公共 HttpUrl url();
// 获取请求方法类型
公共字符串方法();
// 获取请求头
公共标头 headers();
//获取请求体
public RequestBody body();
// 获取标签
公共对象标签();
// 返回缓存控制指令,即使响应不包含 Cache-Control 响应标头,也绝不为 null
公共 CacheControl cacheControl();
// 是否是https请求
public boolean isHttps();
// 请求{method=" ",url=" ",tag = " "}
公共字符串 toString();
这是其Builder
中提供的方法。仅设置.url()
时,默认为post请求。
请求正文
介绍完请求消息,就该介绍请求体了。这与http
协议密切相关。
RequestBody 用于设置请求体。其主要方法是以下静态方法来生成相应的请求体:
就是通过这些方法来生成对应的不同请求体。 MediaType用于描述请求体或响应体类型。例如,请求体类型为字符串格式的json
,则对应的MediaType为 MediaType.parse("application/json; charset=utf-8");
,如果上传文件,然后相应的一个是application/octet-stream
,并且有几种常用的类型文本/plain
imge/pngtext/pngtext/pngtext/ x-markdown 等等。
它还有两个子类别:
FormBody 这个请求体是最常用的一种。我们平时使用post
请求时,参数都是键值对的形式。使用此请求正文是最简单的。
说得深一点,对应的请求消息是:
POST /测试 HTTP/1.1 请求行
Host: 32.106.24.148:8080 以下为请求头
Content-Type:application/x-www-form-urlencoded 用于指示请求体的类型。
用户代理:PostmanRuntime/7.15.0
接受:*/*
缓存控制:无缓存
邮递员令牌:954bda0d-dbc2-4193-addf-a7631cab2cfa,5ba2ebed-90b4-4f35-bcf5-80c4777de471
主机:39.106.24.148:8080
接受编码:gzip、deflate
内容长度:133
连接:保持活动
缓存控制:无缓存
key0=value0&key1=value1 请求体(也是我们的参数)
这是发送的原始消息格式。如果用代码实现的话就是
//创建客户端
OkHttpClient 客户端 = new OkHttpclient();
//创建请求体
FormBody formBody = new FormBody.Builder()
.add("key0", "value0")
.add("key1","value1")
.build();
//创建请求消息
请求请求=新的Request.Builder
.post(formBody)
.url("请求网址")
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("用户代理", "PostmanRuntime/7.15.0")
.addHeader("接受", "*/*")
.addHeader("缓存控制", "无缓存")
.addHeader("邮差令牌", "954bda0d-dbc2-4193-addf-a7631cab2cfa,af7c027c-a7ba-4560-98ae-3a2a473ab88a")
.addHeader("主机", "39.106.24.148:8080")
.addHeader("接受编码", "gzip, deflate")
.addHeader("内容长度", "133")
.addHeader("连接", "保持活动")
.addHeader("缓存控制", "无缓存")
.build();
// 发起请求
client.newCall(request).excute();
上面使用了FormBody
的形式。如果使用RequestBody,那就比较麻烦了。
OkHttpClient 客户端 = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "key0=value0&key1=value1");
请求request = new Request.Builder()
.url("http://39.106.24.148:8080/test")
.post(正文)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("用户代理", "PostmanRuntime/7.15.0")
.addHeader("接受", "*/*")
.addHeader("缓存控制", "无缓存")
.addHeader("邮差令牌", "954bda0d-dbc2-4193-addf-a7631cab2cfa,af7c027c-a7ba-4560-98ae-3a2a473ab88a")
.addHeader("主机", "39.106.24.148:8080")
.addHeader("接受编码", "gzip, deflate")
.addHeader("内容长度", "133")
.addHeader("连接", "保持活动")
.addHeader("缓存控制", "无缓存")
.build();
响应response = client.newCall(request).execute();
当然,我们平时使用的时候,不需要放那么多请求头。我写的目的是为了更方便的还原请求消息。
还有一个子类MultipartBody
这可用于构建更复杂的请求主体。
1995 年,Content-Type 类型扩展为multipart/form-data
,以支持向服务器发送二进制数据。如果一次提交多种类型的数据,比如图片、文字,此时就引入了boundary
,boundary
可以让POST满足提交多种不同数据的需求类型。 。通过boundary
,一个Request中可以同时存在多种不同类型的数据。两个boundary
之间是一种数据,可以重置Content-Type
兼容HTML文件上传表单。每个请求体都是一个请求体,可以定义自己的请求头。这些请求头可以用来描述这个请求。例如,他们的内容处置。如果可用,Content-Length 和 Content-Type 会自动添加到请求标头中。
我们来看看这种类型的请求消息是什么样的:
POST /web/UploadServlet HTTP/1.1
内容类型:多部分/表单数据;边界=e1b05ca4-fc4e-4944-837d-cc32c43c853a
内容长度:66089
主机:www.introzo.com:8080
连接:保持活动状态
接受编码:gzip
用户代理:okhttp/3.5.0
–e1b05ca4-fc4e-4944-837d-cc32c43c853a
内容处置:表单数据;名称=“文件”;文件名=“**.png”
内容类型:image/png
内容长度:65744
fdPNG
IHDR�0B7M�iM�M�CCPIM�CC ProfileH……………………IEND�B`�
–e1b05ca4-fc4e-4944-837d-cc32c43c853a
内容处置:表单数据;名称=“评论”
内容长度: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("内容处置", "表单数据;name=\"标题\""),
RequestBody.create(null, "方形徽标"))
.addPart(
headers.of("Content-Disposition", "form-data;name=\"imge\""),
RequestBody.create(mediaType, new File("path/logo.png"))
).
构建();
请求 request = new Request.Builder()
.post(requestBody)
.url("https://www.introzo.com/3/image")
.build();
尝试一下{
mOkHttpClient.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
简写:
MediaType mediaType = MediaType.parse("image/png");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("标题","徽标")
.addFormDataPart("img","logo.png",RequestBody.create(mediaType,new File("path/logo.png")))
.build();
Content-Disposition 可用于消息正文的子部分,以提供有关其相应字段的信息。作为多部分正文中的消息头,第一个参数始终是固定的表单数据;附加参数不区分大小写并且具有参数值。参数名和参数值用等号连接,参数之间用分隔符分隔。用数字分隔。参数值用双引号括起来
//比如这是固定格式
"Content-Disposition","form-data;name=\"mFile\";filename=\"www.introzo.com4\""
对几个重要请求类别的讨论到此结束。
总结
只要了解了http请求的原理,使用okhttp就不成问题了。
首先,OkHttpClient用于设置请求工具的一些参数,比如超时、是否缓存等。
Call对象是发起Http请求的对象。请求是通过Call对象发起的。
发起请求时,需要请求消息。 Request对象就是对应的请求消息。您可以添加相应的请求行、请求头和请求体。
说到请求体,它对应于RequestBody。那么网络请求过程就完成了!
-->
相关文章
- 10-05 什么是共享单车黑名单制度?共享单车黑名单制度
- 10-05 如何开启Android手机的便携式热点功能
- 10-05 360n5s发布会直播地址360n5s新品发布会视
- 10-05 【第200期】面试官:您能简单讲一下SpringM
- 10-05 【第411期】Docker连杀15题,你能坚持哪题
- 10-05 【第432期】面试官:您的项目中使用Redis的目
- 10-05 ZEEKR 001 FR高性能车型预热:搭载4电机
- 10-05 我国网民规模达10.79亿,互联网普及率达76.4
- 10-05 《2023年标准地图》正式上线
- 10-05 stm32内存包括哪些类型(stm32内存分为几个
- 10-05 stm32采集+数据处理程序(stm32采集+数据
- 10-05 stm32仿真图的引脚如何连接(stm32仿真器接
- 10-05 Zabbix警告问题
- 10-05 Zabbix集成云预警(瑞祥云)实现电话短信预警
- 10-05 利用企业微信实现预警(shell+python)
- 10-05 高通CEO爆料苹果自研5G芯片明年准备就绪
- 10-05 全球智能手机市场被扰乱:iPhone与Androi
- 10-05 苹果最新巧克力广告:Apple Card激活到付款
- 10-05 苹果推出iOS 15.6正式版固件:我们来看看iO
- 10-05 iPadOS 16 允许应用程序使用 M1 设备存
- 最近发表