OkHttp
是目前App
较为常用的一种网络请求框架,使用Okhttp
请求数据内容可以有效的节省服务贷款,提升访问速度,目前OkHttp
支持如下请求:
HTTP / 2
支持允许对同一主机的所有请求共享一个套接字。- 连接池可减少请求延迟(如果
HTTP / 2
不可用)。 - 透明的
GZIP
缩小了下载大小。 - 响应缓存可以完全避免网络重复请求。
OkHttp
的使用较为简单。他只是同步阻塞调用和异步方法回调。如下,通过示例来简单介绍如何用OkHttp
来完成一次Get
请求和Post
请求操作(示例代码为Kotlin
代码实现)。
GET 请求
Get
请求可通过同步阻塞请求获取也可以通过异步方法回调获取,如下为这两种实现方式的实现示例代码:
- 同步阻塞请求
同步阻塞可在当前代码块内获取,适用于直接获取返回数据的情景下:
private val client = OkHttpClient()
fun run() {
val request = Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
for ((name, value) in response.headers) {
println("$name: $value")
}
println(response.body!!.string())
}
}
- 异步方法回调
异步方法回调适用于监听类数据,可通过数据回调监听返回:
private val client = OkHttpClient()
fun run() {
val request = Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
for ((name, value) in response.headers) {
println("$name: $value")
}
println(response.body!!.string())
}
}
})
}
POST请求
POST
请求内容有很多种,一般常见的有如下:
- 字符串(
string
)
字符串请求比较常见,也是我们用的最多的请求方式,一般有数据参数请求(header
),和请求体字符串请求,请求类型有可能是text\json\markdown
等,示例代码如下:
private val client = OkHttpClient()
fun run() {
val postBody = """
|Releases
|--------
|
| * _1.0_ May 6, 2013
| * _1.1_ June 15, 2013
| * _1.2_ August 11, 2013
|""".trimMargin()
val request = Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(postBody.toRequestBody(MEDIA_TYPE_MARKDOWN))
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body!!.string())
}
}
companion object {
val MEDIA_TYPE_MARKDOWN = "text/x-markdown; charset=utf-8".toMediaType()
}
post
请求需要在请求体内声明请求类型和编码方式。
- 文件(
file
)
若是单独按类型而言的话,其实文件类型和流类型有重复部分,我们其实也可以通过将文件转换为流的方式进行请求传递,也可以将文件分成多块进行请求,如下:
// 小文件传输
private val client = OkHttpClient()
fun run() {
val file = File("README.md")
val request = Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(file.asRequestBody(MEDIA_TYPE_MARKDOWN))
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body!!.string())
}
}
companion object {
val MEDIA_TYPE_MARKDOWN = "text/x-markdown; charset=utf-8".toMediaType()
}
- 流(
streaming
)
流的传输常见于文件传输,示例如下:
private val client = OkHttpClient()
fun run() {
val requestBody = object : RequestBody() {
override fun contentType() = MEDIA_TYPE_MARKDOWN
override fun writeTo(sink: BufferedSink) {
sink.writeUtf8("Numbers\n")
sink.writeUtf8("-------\n")
for (i in 2..997) {
sink.writeUtf8(String.format(" * $i = ${factor(i)}\n"))
}
}
private fun factor(n: Int): String {
for (i in 2 until n) {
val x = n / i
if (x * i == n) return "${factor(x)} × $i"
}
return n.toString()
}
}
val request = Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body!!.string())
}
}
companion object {
val MEDIA_TYPE_MARKDOWN = "text/x-markdown; charset=utf-8".toMediaType()
}
- 分段传输(
multipart
)
多段传输常见于传输文件(如图片、视频传输等),这对于文件的断点续传操作有很好的兼容
private val client = OkHttpClient()
fun run() {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("title", "Square Logo")
.addFormDataPart("image", "logo-square.png",
File("docs/images/logo-square.png").asRequestBody(MEDIA_TYPE_PNG))
.build()
val request = Request.Builder()
.header("Authorization", "Client-ID $IMGUR_CLIENT_ID")
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body!!.string())
}
}
companion object {
/**
* The imgur client ID for OkHttp recipes. If you're using imgur for anything other than running
* these examples, please request your own client ID! https://api.imgur.com/oauth2
*/
private val IMGUR_CLIENT_ID = "9199fdef135c122"
private val MEDIA_TYPE_PNG = "image/png".toMediaType()
}
- 常见
json
类型请求
public static final MediaType JSON
= MediaType.get("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, String json) throws IOException {
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}