优点:
1、支持HTTP/2,允许所有同一个主机地址上的请求,共享同一个socket链接
2、连接池——减少请求延时
3、透明的gzip压缩——减少响应数据的大小,减少流量并提高效率
4、缓存响应内容,避免一些完全重复的请求
网络出现问题,okhttp会自动尝试配置的其他ip。Okhttp使用TLS(SNI,ALPN)技术初始化新的连接,当握手失败时会退到TLS1.0.
那么,什么是TLS SNI ALPN 呢?
网络分为七层:
TLS/SSL是在传输层之上应用层之下。但是这个需要CA,如果想让自己的服务也支持HTTPS,那么就要去CA注册寄己的域名。有一些是免费的,比如:GoDaddy, Let’s Encrypt, CloudFlare 等。
看见了么,SNI和ALPN是TLS众多扩展协议中的两种。
导入
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
现在是3.11.0,具体的请根据官网导入官方地址 https://github.com/square/okhttp
okhttp使用一般是用okhttpClient去newCall,但是需要一个request参数。然后再用call去操作下面具体的内容
1、异步get:
/**
* 异步get
*/
OkHttpClient okHttpClient = new OkHttpClient();
Request.Builder builder = new Request.Builder();
Request request = builder.url(url).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());
}
});
2、同步get:
/**
* 同步get 会阻塞,要新建线程
*/
OkHttpClient okHttpClient1 = new OkHttpClient();
Request.Builder builder1 = new Request.Builder();
Request request1 = builder1.url(url).get().build();
final Call call1 = okHttpClient1.newCall(request1);
new Thread(new Runnable() {
@Override
public void run() {
try {
Response response = call1.execute();
Log.d(Tag, "同步get: " + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
3、POST方式提交String
post方式需要提交一个请求体,这个请求体是放在请求里的,而且需要指定具体类型
/**
* post 提交string
*/
final MediaType mediaType = MediaType.parse("text/x-markdown;charset=utf-8");
//发送给服务器的String内容
final String content = "Love";
final Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(new RequestBody() {
@Override
public MediaType contentType() {
return mediaType;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8(content);
}
}).build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(Tag, "onFailure: "+e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Headers headers = response.headers();
for (int i=0;i<headers.size();i++){
Log.d(Tag, headers.name(i) + ";" + headers.value(i));
}
Log.d(Tag, "onesponse:" + response.body().toString());
}
});
4、POST提交流
/**
* post方式提交流
*/
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new RequestBody() {
@Override
public MediaType contentType() {
return MediaType.parse("text/x-markdown;charset=utf-8");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("love");
}
};
Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(requestBody).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(Tag, "onFailure: "+e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Headers headers = response.headers();
for (int i=0;i<headers.size();i++){
Log.d(Tag, headers.name(i) + ";" + headers.value(i));
}
Log.d(Tag, "onResponse:" + response.body().string());
}
});
5、POST提交文件
/**
* post提交文件
*/
File file = new File(getFilesDir().getPath().toString()+"/test.md");
boolean newFile = false;
if (!file.exists()){
try {
newFile= file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("newFile: "+newFile);
System.out.println();
OkHttpClient okHttpClient = new OkHttpClient();
MediaType mediaType = MediaType.parse("text/x-markdown;charset=utf-8");
Request request = new Request.Builder().url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType,file))
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(Tag, "onFailure: "+e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Headers headers = response.headers();
for (int i=0;i<headers.size();i++){
Log.d(Tag, headers.name(i) + ";" + headers.value(i));
}
Log.d(Tag, "onResponse:" + response.body().string());
}
});
6、post提交表单
/**
* post提交表单
*/
OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("testname","testpassword")
.build();
Request request=new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(Tag, "onFailure: "+e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Headers headers = response.headers();
for (int i=0;i<headers.size();i++){
Log.d(Tag, headers.name(i) + ";" + headers.value(i));
}
Log.d(Tag, "onResponse:" + response.body().string());
}
});
7、post提交分块请求
/**
* post提交分块请求
*/
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File(getFilesDir().getPath().toString()+"/test.png");
boolean newFile = false;
if (!file.exists()){
try {
newFile= file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("newFile: "+newFile);
System.out.println();
RequestBody body=new MultipartBody.Builder("AaB03x")
.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=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG,file))
.build();
Request request=new Request.Builder()
.url("https://api.imgur.com/3/image")
.post(body)
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.e(Tag, "onFailure: "+e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Headers headers = response.headers();
for (int i=0;i<headers.size();i++){
Log.d(Tag, headers.name(i) + ";" + headers.value(i));
}
Log.d(Tag, "onResponse:" + response.body().string());
}
});
8、拦截器-interceptor
两类:全局interceptor——通过OkHttpClient.Builder#addInterceptor(Interceptor)
传入
非网页请求interceptor——
参考文献:https://www.jianshu.com/p/da4a806e599b
这类拦截器只会在非网页请求中被调用,并且是在组装完请求之后,真正发起网络请求前被调用,所有的 interceptor
被保存在 List<Interceptor> interceptors
集合中,按照添加顺序来逐个调用,具体可参考 RealCall#getResponseWithInterceptorChain()
方法。通过 OkHttpClient.Builder#addNetworkInterceptor(Interceptor)
传入;
举例:
监控app通过okhttp发出的所有原始请求及整个请求耗费时间,这里使用第一类拦截器:
/**
* 拦截器 第一类 监控原始请求信息和耗费时间
*/
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
Request request=new Request.Builder()
.url("http://www.publicobject.com/helloworld.txt")
.header("User-Agent","Okhttp Example")
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
}
private class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.nanoTime();
Log.d(Tag, String.format("Sending request %s on %s%n%s"
, request.url(), chain.connection(),request.headers()));
Response response = chain.proceed(request);
long endTime = System.nanoTime();
Log.d(Tag, String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
return response;
}
}
其实还是有疑问的。。比如原作者的
Received response for %s in %.1fms%n%s 对应的 1e6d
个人分析应该是一种时间转换方法。
毕竟System.nanoTime()是按纳秒计算的
另外,当你把addInterceptor换为addNetworkInterceptor,你会发现他的重定向你也能看到啦。
9、自定义dns服务
默认是使用系统的
另外一般okHttpClient是使用单例的,因为他有线程池。
另外每一个call只能执行一次否则会报异常。具体参见RealCall#execute()。
再次对原作者表示感谢,这里只是用于学习记录和总结。来源:https://www.jianshu.com/p/da4a806e599b