OkHttp #
一、OkHttp概述 #
OkHttp是Square公司开源的高性能HTTP客户端,是Android开发中最常用的网络库之一。
1.1 OkHttp特点 #
- 支持HTTP/2
- 连接池减少延迟
- 透明的GZIP压缩
- 响应缓存
- 拦截器机制
- 支持WebSocket
1.2 添加依赖 #
kotlin
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
二、基本使用 #
2.1 创建OkHttpClient #
kotlin
// 简单创建
val client = OkHttpClient()
// 自定义配置
val client = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build()
2.2 GET请求 #
kotlin
suspend fun get(url: String): String {
val request = Request.Builder()
.url(url)
.get()
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw IOException("Unexpected code $response")
}
return response.body?.string() ?: ""
}
}
// 异步请求
fun getAsync(url: String, callback: Callback) {
val request = Request.Builder()
.url(url)
.get()
.build()
client.newCall(request).enqueue(callback)
}
2.3 POST请求 #
kotlin
// JSON请求
suspend fun postJson(url: String, json: String): String {
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = json.toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.post(body)
.build()
client.newCall(request).execute().use { response ->
return response.body?.string() ?: ""
}
}
// 表单请求
suspend fun postForm(url: String, params: Map<String, String>): String {
val formBody = FormBody.Builder().apply {
params.forEach { (key, value) ->
add(key, value)
}
}.build()
val request = Request.Builder()
.url(url)
.post(formBody)
.build()
client.newCall(request).execute().use { response ->
return response.body?.string() ?: ""
}
}
// Multipart上传文件
suspend fun uploadFile(url: String, file: File): String {
val mediaType = "image/jpeg".toMediaType()
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.name, file.asRequestBody(mediaType))
.addFormDataPart("description", "File upload")
.build()
val request = Request.Builder()
.url(url)
.post(requestBody)
.build()
client.newCall(request).execute().use { response ->
return response.body?.string() ?: ""
}
}
2.4 添加请求头 #
kotlin
val request = Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer $token")
.addHeader("Content-Type", "application/json")
.header("User-Agent", "MyApp/1.0") // 覆盖同名header
.build()
三、拦截器 #
3.1 日志拦截器 #
kotlin
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
3.2 自定义拦截器 #
kotlin
class AuthInterceptor(private val token: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer $token")
.build()
return chain.proceed(request)
}
}
val client = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor("your_token"))
.build()
3.3 响应拦截器 #
kotlin
class ResponseInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
// 检查token是否过期
if (response.code == 401) {
// 刷新token并重试
val newToken = refreshToken()
val newRequest = chain.request().newBuilder()
.header("Authorization", "Bearer $newToken")
.build()
return chain.proceed(newRequest)
}
return response
}
}
3.4 缓存拦截器 #
kotlin
class CacheInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val newRequest = request.newBuilder()
.header("Cache-Control", "public, max-age=60")
.build()
return chain.proceed(newRequest)
}
}
3.5 网络拦截器 vs 应用拦截器 #
kotlin
val client = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor) // 应用拦截器
.addNetworkInterceptor(networkInterceptor) // 网络拦截器
.build()
| 特性 | 应用拦截器 | 网络拦截器 |
|---|---|---|
| 调用次数 | 一次 | 可能多次(重定向、重试) |
| 缓存 | 不触发缓存 | 触发缓存 |
| 网络状态 | 不关心 | 可检查网络状态 |
四、缓存 #
4.1 配置缓存 #
kotlin
val cacheSize = 10 * 1024 * 1024L // 10MB
val cacheDir = File(context.cacheDir, "http_cache")
val cache = Cache(cacheDir, cacheSize)
val client = OkHttpClient.Builder()
.cache(cache)
.build()
4.2 缓存策略 #
kotlin
// 强制使用缓存
val request = Request.Builder()
.url(url)
.cacheControl(CacheControl.FORCE_CACHE)
.build()
// 强制使用网络
val request = Request.Builder()
.url(url)
.cacheControl(CacheControl.FORCE_NETWORK)
.build()
// 自定义缓存策略
val cacheControl = CacheControl.Builder()
.maxAge(10, TimeUnit.MINUTES)
.build()
val request = Request.Builder()
.url(url)
.cacheControl(cacheControl)
.build()
五、Cookie管理 #
5.1 持久化Cookie #
kotlin
val cookieJar = PersistentCookieJar(SetCookieCache(), SharedPrefsCookiePersistor(context))
val client = OkHttpClient.Builder()
.cookieJar(cookieJar)
.build()
5.2 自定义CookieJar #
kotlin
class MyCookieJar : CookieJar {
private val cookieStore = mutableMapOf<String, List<Cookie>>()
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
cookieStore[url.host] = cookies
}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return cookieStore[url.host] ?: emptyList()
}
}
六、WebSocket #
6.1 创建WebSocket #
kotlin
val client = OkHttpClient()
val request = Request.Builder()
.url("wss://example.com/ws")
.build()
val webSocket = client.newWebSocket(request, object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
Log.d("WebSocket", "Connected")
}
override fun onMessage(webSocket: WebSocket, text: String) {
Log.d("WebSocket", "Received: $text")
}
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
webSocket.close(1000, null)
Log.d("WebSocket", "Closing: $code / $reason")
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Log.e("WebSocket", "Error", t)
}
})
// 发送消息
webSocket.send("Hello")
// 关闭连接
webSocket.close(1000, "Goodbye")
七、封装工具类 #
kotlin
object OkHttpUtils {
private val client: OkHttpClient by lazy {
OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.build()
}
suspend fun get(url: String, headers: Map<String, String> = emptyMap()): Result<String> {
return withContext(Dispatchers.IO) {
try {
val request = Request.Builder()
.url(url)
.apply {
headers.forEach { (key, value) ->
addHeader(key, value)
}
}
.get()
.build()
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
Result.success(response.body?.string() ?: "")
} else {
Result.failure(Exception("HTTP ${response.code}"))
}
}
} catch (e: Exception) {
Result.failure(e)
}
}
}
suspend fun post(url: String, json: String, headers: Map<String, String> = emptyMap()): Result<String> {
return withContext(Dispatchers.IO) {
try {
val mediaType = "application/json; charset=utf-8".toMediaType()
val body = json.toRequestBody(mediaType)
val request = Request.Builder()
.url(url)
.apply {
headers.forEach { (key, value) ->
addHeader(key, value)
}
}
.post(body)
.build()
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
Result.success(response.body?.string() ?: "")
} else {
Result.failure(Exception("HTTP ${response.code}"))
}
}
} catch (e: Exception) {
Result.failure(e)
}
}
}
}
八、最佳实践 #
8.1 单例OkHttpClient #
kotlin
object HttpClient {
val client: OkHttpClient = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build()
}
8.2 使用协程扩展 #
kotlin
suspend fun Call.await(): Response {
return suspendCancellableCoroutine { continuation ->
enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
continuation.resumeWithException(e)
}
override fun onResponse(call: Call, response: Response) {
continuation.resume(response)
}
})
continuation.invokeOnCancellation {
cancel()
}
}
}
// 使用
val response = client.newCall(request).await()
8.3 错误处理 #
kotlin
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val code: Int, val message: String) : NetworkResult<Nothing>()
data class Exception(val e: Throwable) : NetworkResult<Nothing>()
}
suspend fun <T> safeApiCall(block: suspend () -> T): NetworkResult<T> {
return try {
NetworkResult.Success(block())
} catch (e: IOException) {
NetworkResult.Exception(e)
} catch (e: HttpException) {
NetworkResult.Error(e.code(), e.message())
}
}
九、总结 #
本章详细介绍了OkHttp:
- OkHttp的基本使用
- GET、POST请求
- 拦截器机制
- 缓存配置
- Cookie管理
- WebSocket支持
- 工具类封装
- 最佳实践
OkHttp是Android网络请求的基础库,配合Retrofit使用可以大大提高开发效率。
最后更新:2026-03-26