配置
compile 'com.squareup.okhttp3:okhttp:3.4.1'
GET
首先是以同步的方式执行请求
//创建一个request
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) { //请求成功
Log.d(TAG, "testGet: " + response.body().string());
} else {
throw new IOException("" + response.code());
}
以上就是执行GET请求的方法。
- 构造一个Request对象,参数最起码有个url,当然你可以通过Request.Builder设置更多的参数比如:header、method等。
- 通过request的对象去构造得到一个Call对象,类似于将你的请求封装成了任务,既然是任务,就会有execute()和cancel()等方法。
- 当前我们使用的是同步的方法,即调用call的execute()方法。若希望以异步的方式去执行请求,我们可以调用call.enqueue,将call加入调度队列,然后等待任务执行完成,我们在Callback中即可得到结果。
- onResponse回调的参数是response,一般情况下,比如我们希望获得返回的字符串,可以通过response.body().string()获取;如果希望获得返回的二进制字节数组,则调用response.body().bytes();如果你想拿到返回的inputStream,则调用response.body().byteStream()。
- 图片下载,通过回调的Response拿到byte[]然后decode成图片;文件下载,就是拿到inputStream做写文件操作。
异步执行请求
call.enqueue(new Callback()
{
//请求失败
@Override
public void onFailure(Request request, IOException e)
{
}
//得到响应时
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
}
});
为Request添加请求头
Request request = new Request.Builder()
.url("http://www.baidu.com")
.addHeader("User-Agent","android")
.header("Content-Type","text/html; charset=utf-8")
.build();
若想要为GET请求添加参数的话可以使用HttpUrl类来构造url
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
urlBuilder.addQueryParameter("KEY", "VALUE");
HttpUrl httpUrl = urlBuilder.build();
POST
post请求的执行也可以同步或者异步,参考GET请求。简便起见,这里默认用同步方法。
POST 提交json字符串
设置MediaType
MediaType mediaType = Medi2aType.parse("application/json; charset=utf-8");
执行post请求
private Response post(String url, String json) throws IOException {
RequestBody requestBody = RequestBody.create(mediaType, json);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
return response;
}
- 通过RequestBody.create(MediaType contentType, String content)方法来构造RequestBody, contentType代表了上传内容的类型,content即上传的json字符串
- 使用Request的post方法来提交请求体RequestBody
POST 提交键值对
很多时候我们需要向服务器提交键值对。这是构造RequestBody的方法就与上面说的不同了。当然,这里介绍的时OkHttp3的方法
1. 通过FormBody.Builder()创建一个构造器,它的add()方法添加键值对,再通过build方法来构造一个FormBody。
2. FormBody的父类为RequestBody,所以我们可以将FormBody作为请求体使用。
RequestBody formBody = new FormBody.Builder()
.add("name1", "value1")
.add("name2", "value2")
.build();
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 {
RequestBody requestBody = new RequestBody() {
//设置ContentType
@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, (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());
}
这里直接向Buffered Sink中写入流,若更喜欢使用OutputStream,请使用BufferedSink.outputStream()
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());
}
若不确定文件的类型,可通过以下方法获得文件类型
private static final MediaType MEDIA_TYPE = MediaType.parse(judgeType(fileName);
private String judgeType(String path) {
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String contentTypeFor = fileNameMap.getContentTypeFor(path);
if (contentTypeFor == null) {
contentTypeFor = "application/octet-stream";
}
return contentTypeFor;
}
POST 多种类型的body
通过MultipartBody.addPart(),MultipartBody.addFormDataPart()实现。每个Part都是它所属的RequestBody的一个请求体,因此,它们也可以拥有自己的headers。通过MultipartBody.setType()方法,可以设置MultipartBody的类型
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("title", "Square Logo")
.addFormDataPart("image", "logo-square.png",
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
提取响应头
典型的HTTP头 像是一个Map<String, String>
每个字段都有一个或没有值。但是一些头允许多个值,像Guava的Multimap。例如:HTTP响应里面提供的Vary响应头,就是多值的。OkHttp的api试图让这些情况都适用。
当写请求头的时候,使用header(name, value)
可以设置唯一的name、value。如果已经有值,旧的将被移除,然后添加新的。使用addHeader(name, value)
可以添加多值(添加,不移除已有的)。
当读取响应头时,使用header(name)
返回最后出现的name、value。通常情况这也是唯一的name、value。如果没有值,那么header(name)
将返回null。如果想读取字段对应的所有值,使用headers(name)
会返回一个list。
参考
Android OkHttp完全解析 是时候来了解OkHttp了
OkHttp使用进阶 译自OkHttp Github官方教程
okhttp教程——起步篇
OkHttp使用教程