前言
我们在添加响应切面后原接口无法接收响应的问题,核心原因是
OkHttp 的 ResponseBody 是一次性流(仅能读取一次)
也就是说代码中调用了 body.string() 读取响应体,导致流被耗尽,后续 Retrofit 解析响应时,流已无数据可读,最终接口无法获取结果。
这里的解决方法是
重新构建 ResponseBody
拦截器
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| import android.util.Log import com.google.gson.Gson import com.xhkjedu.zxs_android.common.CommonData import com.xhkjedu.zxs_android.model.ResultVoNoData import com.xhkjedu.zxs_android.utils.SPUtil import com.xhkjedu.zxs_android.utils.eventbus.ZEventExitLogin import com.xhkjedu.zxs_android.utils.eventbus.ZFlowEventBus import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.Response import okhttp3.ResponseBody import okhttp3.ResponseBody.Companion.toResponseBody
class HeaderInterceptor : Interceptor { val TAG: String = "HeaderInterceptor"
override fun intercept(chain: Interceptor.Chain): Response { val original = chain.request() try { val mBuilder = original.newBuilder() if (CommonData.Authorization != "") { mBuilder.header("Authorization", CommonData.Authorization) }
val request = mBuilder .method(original.method, original.body) .build()
val response = chain.proceed(request) val headers = response.headers headers.forEach { header -> if (header.first == "Authorization") { CommonData.Authorization = header.second SPUtil.putString("Authorization", header.second) } }
return handleResponse(response) } catch (_: Exception) { return chain.proceed(original) } }
class InterceptorCoroutineScope : CoroutineScope { private val job = Job()
override val coroutineContext = Dispatchers.IO + job + CoroutineName("InterceptorScope")
fun cancelScope() { job.cancel() } }
private fun handleResponse(response: Response): Response { val statusCode = response.code if (statusCode == 200) { val body = response.body body?.let { val contentType = it.contentType()?.toString() ?: "" if (contentType.contains("application/json")) { val responseStr = it.string() try { val resultVoNoData = Gson().fromJson(responseStr, ResultVoNoData::class.java) if (resultVoNoData.code == 2) { val scope = InterceptorCoroutineScope() try { runBlocking(scope.coroutineContext) { launch { ZFlowEventBus.post(ZEventExitLogin()) } } } finally { scope.cancelScope() } } } catch (_: Exception) { Log.e(TAG, "handleResponse: 解析失败") } val newBody: ResponseBody? = responseStr .toResponseBody(it.contentType()) return response.newBuilder().body(newBody).build() } }
} return response } }
|
响应处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
private fun handleResponse(response: Response): Response { val statusCode = response.code if (statusCode == 200) { val body = response.body if (body != null) { val responseStr = body.string()
val newBody: ResponseBody? = responseStr .toResponseBody(it.contentType()) return response.newBuilder().body(newBody).build() } } return response }
|
自定义协程
1 2 3 4 5 6 7 8 9 10 11 12
| class InterceptorCoroutineScope : CoroutineScope { private val job = Job()
override val coroutineContext = Dispatchers.IO + job + CoroutineName("InterceptorScope")
fun cancelScope() { job.cancel() } }
|
协程使用
1 2 3 4 5 6 7 8 9 10 11
| val scope = InterceptorCoroutineScope() try { runBlocking(scope.coroutineContext) { launch { ZFlowEventBus.post(ZEventExitLogin()) } } } finally { scope.cancelScope() }
|
设置拦截器
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import android.annotation.SuppressLint import com.xhkjedu.zxs_android.common.CommonData import okhttp3.OkHttpClient import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.security.SecureRandom import java.util.concurrent.TimeUnit import javax.net.ssl.HostnameVerifier import javax.net.ssl.SSLContext import javax.net.ssl.TrustManager import javax.net.ssl.X509TrustManager
object ApiManager { private lateinit var commonRetrofit: Retrofit
lateinit var userService: ServiceUser
init { if (!::commonRetrofit.isInitialized) { val client = getUnsafeOkHttpClient().newBuilder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .addInterceptor(HeaderInterceptor()) .build();
commonRetrofit = Retrofit.Builder() .baseUrl(CommonData.apiUrl) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() }
if (!::userService.isInitialized) { userService = commonRetrofit.create(ServiceUser::class.java) }
}
@SuppressLint("CustomX509TrustManager") fun getUnsafeOkHttpClient(): OkHttpClient { try { val trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager { override fun checkClientTrusted( chain: Array<out java.security.cert.X509Certificate>?, authType: String? ) { }
override fun checkServerTrusted( chain: Array<out java.security.cert.X509Certificate>?, authType: String? ) { }
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf() } )
val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustAllCerts, SecureRandom())
val allHostsValid = HostnameVerifier { _, _ -> true }
return OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) .hostnameVerifier(allHostsValid) .build() } catch (e: Exception) { throw RuntimeException(e) } } }
|
跳过证书验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @SuppressLint("CustomX509TrustManager") fun getUnsafeOkHttpClient(): OkHttpClient { try { val trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager { override fun checkClientTrusted( chain: Array<out java.security.cert.X509Certificate>?, authType: String? ) { }
override fun checkServerTrusted( chain: Array<out java.security.cert.X509Certificate>?, authType: String? ) { }
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> = arrayOf() } )
val sslContext = SSLContext.getInstance("TLS") sslContext.init(null, trustAllCerts, SecureRandom())
val allHostsValid = HostnameVerifier { _, _ -> true }
return OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) .hostnameVerifier(allHostsValid) .build() } catch (e: Exception) { throw RuntimeException(e) } }
|
Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import retrofit2.Response import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.POST
interface ServiceUser { data class LoginPara( var username: String = "", var password: String = "", )
@POST("/api/auth/login") suspend fun apiAuthLogin(@Body request: LoginPara): Response<ResultVo<UserModel>> }
|