欢迎访问我的主页: https://heeheeaii.github.io/
1. 基础配置
依赖添加
kotlin
// Gradle (build.gradle.kts)
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
单例客户端配置
kotlin
object HttpClient {
val client: OkHttpClient by lazy {
OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(LoggingInterceptor())
.addInterceptor(AuthInterceptor())
.build()
}
}
2. 基本请求方法
GET 请求
kotlin
// 同步 GET
fun getUser(userId: String): String? {
val request = Request.Builder()
.url("https://api.example.com/users/$userId")
.build()
return try {
HttpClient.client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
response.body?.string()
} else {
throw Exception("HTTP ${response.code}: ${response.message}")
}
}
} catch (e: Exception) {
println("请求失败: ${e.message}")
null
}
}
// 异步 GET
fun getUserAsync(userId: String, callback: (String?) -> Unit) {
val request = Request.Builder()
.url("https://api.example.com/users/$userId")
.build()
HttpClient.client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
callback(null)
}
override fun onResponse(call: Call, response: Response) {
response.use {
callback(if (it.isSuccessful) it.body?.string() else null)
}
}
})
}
POST JSON 请求
kotlin
fun createUser(userData: String): String? {
val requestBody = userData.toRequestBody("application/json".toMediaType())
val request = Request.Builder()
.url("https://api.example.com/users")
.post(requestBody)
.build()
return HttpClient.client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
response.body?.string()
} else {
throw Exception("创建失败: ${response.code}")
}
}
}
POST 表单请求
kotlin
fun login(username: String, password: String): String? {
val formBody = FormBody.Builder()
.add("username", username)
.add("password", password)
.build()
val request = Request.Builder()
.url("https://api.example.com/login")
.post(formBody)
.build()
return HttpClient.client.newCall(request).execute().use { response ->
response.body?.string()
}
}
3. 文件操作
文件上传
kotlin
fun uploadFile(file: File, description: String): String? {
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("description", description)
.addFormDataPart("file", file.name,
file.asRequestBody("application/octet-stream".toMediaType()))
.build()
val request = Request.Builder()
.url("https://api.example.com/upload")
.post(requestBody)
.build()
return HttpClient.client.newCall(request).execute().use { response ->
response.body?.string()
}
}
文件下载
kotlin
fun downloadFile(url: String, outputFile: File): Boolean {
val request = Request.Builder().url(url).build()
return try {
HttpClient.client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
response.body?.byteStream()?.use { inputStream ->
outputFile.outputStream().use { outputStream ->
inputStream.copyTo(outputStream)
}
}
true
} else {
false
}
}
} catch (e: Exception) {
false
}
}
// 带进度的下载
fun downloadWithProgress(url: String, outputFile: File,
onProgress: (progress: Int) -> Unit): Boolean {
val request = Request.Builder().url(url).build()
return try {
HttpClient.client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
val body = response.body ?: return false
val contentLength = body.contentLength()
body.byteStream().use { inputStream ->
outputFile.outputStream().use { outputStream ->
val buffer = ByteArray(8192)
var downloaded = 0L
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
downloaded += bytesRead
if (contentLength > 0) {
val progress = (downloaded * 100 / contentLength).toInt()
onProgress(progress)
}
}
}
}
true
} else {
false
}
}
} catch (e: Exception) {
false
}
}
4. 实用拦截器
日志拦截器
kotlin
class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val startTime = System.nanoTime()
println("发送请求: ${request.method} ${request.url}")
val response = chain.proceed(request)
val endTime = System.nanoTime()
println("收到响应: ${response.code} in ${(endTime - startTime) / 1e6}ms")
return response
}
}
认证拦截器
kotlin
class AuthInterceptor(private val token: String) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val authenticatedRequest = originalRequest.newBuilder()
.header("Authorization", "Bearer $token")
.build()
return chain.proceed(authenticatedRequest)
}
}
重试拦截器
kotlin
class RetryInterceptor(private val maxRetries: Int = 3) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
var response = chain.proceed(request)
var retryCount = 0
while (!response.isSuccessful && retryCount < maxRetries) {
retryCount++
println("重试第 $retryCount 次: ${request.url}")
response.close()
response = chain.proceed(request)
}
return response
}
}
缓存拦截器
kotlin
class CacheInterceptor(private val maxAge: Int = 60) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val response = chain.proceed(request)
return response.newBuilder()
.header("Cache-Control", "public, max-age=$maxAge")
.build()
}
}
5. 高级配置
缓存设置
kotlin
val cacheSize = 10 * 1024 * 1024L // 10MB
val cache = Cache(File(context.cacheDir, "http-cache"), cacheSize)
val clientWithCache = OkHttpClient.Builder()
.cache(cache)
.addNetworkInterceptor(CacheInterceptor())
.build()
HTTPS 配置
kotlin
// 信任所有证书(仅用于开发环境)
fun createUnsafeClient(): OkHttpClient {
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
})
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
return OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
.hostnameVerifier { _, _ -> true }
.build()
}
// 证书锁定(生产环境推荐)
val clientWithPinning = OkHttpClient.Builder()
.certificatePinner(
CertificatePinner.Builder()
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build()
)
.build()
6. 工具类封装
HTTP 工具类
kotlin
class HttpUtil private constructor() {
companion object {
private val client = OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.build()
// GET 请求
fun get(url: String, headers: Map<String, String> = emptyMap()): String? {
val requestBuilder = Request.Builder().url(url)
headers.forEach { (key, value) ->
requestBuilder.addHeader(key, value)
}
return try {
client.newCall(requestBuilder.build()).execute().use { response ->
if (response.isSuccessful) response.body?.string() else null
}
} catch (e: Exception) {
null
}
}
// POST JSON
fun postJson(url: String, json: String, headers: Map<String, String> = emptyMap()): String? {
val requestBody = json.toRequestBody("application/json".toMediaType())
val requestBuilder = Request.Builder().url(url).post(requestBody)
headers.forEach { (key, value) ->
requestBuilder.addHeader(key, value)
}
return try {
client.newCall(requestBuilder.build()).execute().use { response ->
if (response.isSuccessful) response.body?.string() else null
}
} catch (e: Exception) {
null
}
}
// 异步请求
fun getAsync(url: String, callback: (String?) -> Unit) {
val request = Request.Builder().url(url).build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
callback(null)
}
override fun onResponse(call: Call, response: Response) {
response.use { callback(if (it.isSuccessful) it.body?.string() else null) }
}
})
}
}
}
API 响应包装类
kotlin
data class ApiResponse<T>(
val code: Int,
val message: String,
val data: T?
) {
val isSuccess: Boolean get() = code == 200
}
// 使用示例
inline fun <reified T> parseResponse(json: String): ApiResponse<T>? {
return try {
Gson().fromJson(json, object : TypeToken<ApiResponse<T>>() {}.type)
} catch (e: Exception) {
null
}
}
7. 实际使用示例
用户服务示例
kotlin
class UserService {
private val baseUrl = "https://api.example.com"
fun login(email: String, password: String): ApiResponse<String>? {
val loginData = mapOf("email" to email, "password" to password)
val json = Gson().toJson(loginData)
val response = HttpUtil.postJson("$baseUrl/login", json)
return response?.let { parseResponse<String>(it) }
}
fun getUserProfile(token: String): ApiResponse<User>? {
val headers = mapOf("Authorization" to "Bearer $token")
val response = HttpUtil.get("$baseUrl/profile", headers)
return response?.let { parseResponse<User>(it) }
}
fun uploadAvatar(token: String, avatarFile: File, callback: (Boolean) -> Unit) {
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("avatar", avatarFile.name,
avatarFile.asRequestBody("image/*".toMediaType()))
.build()
val request = Request.Builder()
.url("$baseUrl/upload-avatar")
.addHeader("Authorization", "Bearer $token")
.post(requestBody)
.build()
HttpClient.client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
callback(false)
}
override fun onResponse(call: Call, response: Response) {
callback(response.isSuccessful)
}
})
}
}
8. 调试和测试
调试技巧
kotlin
// 详细日志记录
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
// 网络状态监控
class NetworkStatusInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
println("请求: ${request.method} ${request.url}")
println("请求头: ${request.headers}")
val startTime = System.currentTimeMillis()
val response = chain.proceed(request)
val endTime = System.currentTimeMillis()
println("响应: ${response.code} (${endTime - startTime}ms)")
println("响应头: ${response.headers}")
return response
}
}
Mock 数据
kotlin
class MockInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
// 根据 URL 返回模拟数据
return when {
request.url.toString().contains("/users/123") -> {
val mockResponse = """{"id":123,"name":"测试用户"}"""
Response.Builder()
.request(request)
.protocol(Protocol.HTTP_1_1)
.code(200)
.message("OK")
.body(mockResponse.toResponseBody("application/json".toMediaType()))
.build()
}
else -> chain.proceed(request)
}
}
}