OkHttp
- coding
- android
- httpclient
简介
OkHttp 作为一个简洁高效的 HTTP 客户端,可以在 Java 和 Android 程序中使用。相对于 Apache HttpClient 来说,OkHttp 的性能更好,其 API 设计也更加简单实用。
Http Request
一个http request由Request-line(请求行)、Header(消息头)和Message-body(请求实体)组成,后两者之间有一空行隔开,且后两者可以为空,而Request-line不得为空。
举个例子:
POST /index.php HTTP/1.1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0)
Accept: text/html
Accept-Language: zh-cn,zh;q=0.5
Referer: http://localhost/
第一行是请求行,指出了请求的方式为POST,访问的是根目录下的index.php,http版本为1.1。
余下的为消息头,包括user-agent(指明终端类型),accept(终端可以解释的类型),accept-language(浏览器能解释的语言)等等。
在OkHttp库中,通过new Request.Builder().build()来创建Request对象,并且可以通过url()指定url,header()指定消息头细节。
Get方式
实例化OkHttpClient
一般来说,一个app只需要一个OkHttpClient:
OkHttpClient mClient = new OkHttpClient();
Sync get(同步get)
private void syncGet(String url) {
final Request request = new Request.Builder()
.url(url)
.build();
new Thread() {
Response mResponse = null;
@Override
public void run() {
super.run();
try {
mResponse = mClient.newCall(request).execute();
System.out.println(mResponse.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
可以看到,Request通过Request.Builder().build()来生成。可以在生成过程中插入url,header等。
同步方法相当于阻塞当前线程(UI线程),故需要开启子线程。通过OkHttpClient.newCall(request).execute()来访问网络。
Async get(异步get)
private void asyncGet(String url) {
Request request = new Request.Builder()
.url(url)
.build();
mClient.newCall(request).enqueue(mPrintResponseCallback);
}
异步方式,request的生成方式跟同步一样,但是执行使用的是enqueue方法。enqueue字眼说明了是进入线程调度,而不是直接阻塞当前线程。
enqueue方法需要传入一个Callback接口,这里自定义一个Callback接口:
private class printResponseCallback implements Callback {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful())
System.out.println(response.body().string());
}
}
需要重写两个方法,onFailure是访问失败时调用,onResponse是有Response返回时调用的方法,需要注意的是onResponse仍然是运行在工作线程,故不可以直接在此处更新UI。
Post方式
Sync post(同步post)
private void syncPost(String url) {
MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_TEXT, "Hello World");
final Request request = new Request.Builder().url(url).post(requestBody).build();
new Thread(){
Response mResponse = null;
@Override
public void run() {
super.run();
try {
mResponse = mClient.newCall(request).execute();
System.out.println(mResponse.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
post请求需要指定MediaType,通过RequestBody.create(MediaType, String)可以将String类型转换成MediaType类型的RequestBody。
在构建Request时,需要多加post(RequestBody)来添加请求实体。网络请求部分的代码跟get方式一样。
Async post(异步post)
private void asyncPost(String url) {
MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
RequestBody body = RequestBody.create(MEDIA_TYPE_TEXT, "Hello World");
Request request = new Request.Builder().url(url).post(body).build();
mClient.newCall(request).enqueue(mPrintResponseCallback);
}
流方式构建实体
private void postFlow(String url){
final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain");
final String requestBody = "Hello World";
RequestBody body = new RequestBody() {
@Override
public MediaType contentType() {
return MEDIA_TYPE_TEXT;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8(requestBody);
}
};
Request request = new Request.Builder().url(url).post(body).build();
mClient.newCall(request).enqueue(mPrintResponseCallback);
}
这里创建了 RequestBody 的一个匿名子类。该子类的 contentType 方法需要返回内容的媒体类型,而 writeTo 方法的参数是一个 BufferedSink 对象。需要做的就是把请求的内容写入到 BufferedSink 对象。
Http Response
通过上述的几种方法我们都可以得到Response对象。
一个Http Response对象包括:Status-line、若干Header和Message-body,其中后两者可以没有,消息头和实体内容间有一个空行。
举个例子:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 88
Content-Type: text/html
Connection: Closed
通过Response对象,使用response.body()可以获得message-body,通过request.headers可以得到集合对象Headers。利用headers.name(index)和headers.value(index)可以分别得到每个header的名字和值。
总结
正在适应OkHttp。