前言
网络基础知识->socket原理、编程->httpUrlConnection->OkHttp->retrofit,循序渐进
框架图
简介(摘自官网)
HTTP是现代应用常用的一种交换数据和媒体的网络方式,高效地使用HTTP能让资源加载更快,节省带宽。OkHttp是一个高效的HTTP客户端,它有以下默认特性:
- 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
- 连接池减少请求延时
- 透明的GZIP压缩减少响应数据的大小
- 缓存响应内容,避免一些完全重复的请求
- 请求失败时自动重试主机的其他 IP,自动重定向
- 当握手失败时会回退到TLS 1.0
PS:关于Http2.0,阿简认为该大V分析的很好,推荐参考:一文读懂 HTTP/2 特性
总结来说http2有相比于http1.x有以下几个特点:
- HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
- 多路复用,代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP连接并发完成。
- 头部压缩(客户端服务端都建立首部表,每次请求响应只需要发送差异数据,客户端和服务器共同渐进地更新)
使用
- okhttp采用建造者模式设计,使用很方便
GET异步请求
String url = "http://wwww.baidu.com";
//创建一个http客户端对象
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
//发起异步请求
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
GET同步请求
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.build();
final Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call.execute();
Log.d(TAG, "run: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
因为是GET请求,所以没有请求体,只需要请求头和请求行就可以,所以Request中只需要说明请求方法、URL即可(原理可参考:[网络基本知识-http]
(https://www.jianshu.com/p/291819f78a53))
POST方式提交String
使用HTTP POST的请求体发送到服务。下面例子post了一个markdown文档到一个的Web服务(将markdown作为HTML)。由于整个请求体是同时在内存中,应避免使用此API发送较大(大于1 MIB)的文件。
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
POST方式提交Streaming
在这里,我们POST请求体作为stream。正在生成请求体的内容写入到stream中。下面例子streams直接进入 Okio缓冲水槽。你的程序可能更喜欢使用OutputStream,你可以通过BufferedSink.outputStream()获得 OutputStream。
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
RequestBody requestBody = new RequestBody() {
@Override public MediaType contentType() {
return MEDIA_TYPE_MARKDOWN;
}
@Override public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("Numbers\n");
sink.writeUtf8("-------\n");
for (int i = 2; i <= 997; i++) {
sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
}
}
private String factor(int n) {
for (int i = 2; i < n; i++) {
int x = n / i;
if (x * i == n) return factor(x) + " × " + i;
}
return Integer.toString(n);
}
};
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
POST方式提交文件
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
File file = new File("README.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
PS:通过以上POST的三种方式来看,因为post请求如果是提交数据的话一般都会使用到请求体,所以在okhttp中使用post的时候,主要的是两点:1.MediaType 协议 2.构建请求体RequestBody
关于请求报文有疑问的可以参考阿简的这篇文章:网络基本知识-http
拦截器
关于拦截器,阿简写了一篇很通俗易懂的文章方便大家理解:okhttp3拦截器源码逐行分析(okhttp-3.14.4)
END