如何等待挂起函数的结果?



我需要将freshCsrf字符串添加到每个请求到表单体中。OkHttpClientAuthInterceptor共用。问题是如何在拦截器内发送请求以获得freshCsrf字符串?

下面的代码出现错误

Suspend function 'getAuth' should be called only from a coroutine or another suspend function
class AuthInterceptor(val authApi: IAuthService) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val freshCsrf = authApi.getAuth().freshCsrf
// ... add freshCsrf to form body
return chain.proceed(request)
}
}
// Retrofit service
interface IAuthApi {
@GET("/auth")
suspend fun getAuth(): Auth
}

我尝试使用协程,但也失败了,因为不能等待结果。例子之一async/await了错误

Suspend function 'await' should be called only from a coroutine or another suspend function
private val scope = CoroutineScope(Dispatchers.IO)

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val freshCsrf = scope.async { authApi.getAuth().freshCsrf }
freshCsrf.await()

// ... add freshCsrf to form body
return chain.proceed(request)
}

更新1

我混淆了runBlocking的描述

设计用于桥接类库的常规阻塞代码挂起式编写,用于主函数而在测试.

一方面,改装接口暂停,我需要等待网络结果,以便继续创建其他请求(桥接- ok)。但在另一方面,它不是主函数或测试。许多教程和文章都告诉我们必须在产品代码中避免runBlocking。你能解释一下吗?

override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val freshCsrf = runBlocking {
return@runBlocking authApi.getAuth().freshCsrf
}

// ... add freshCsrf to form body
return chain.proceed(request)
}

使用.execute()代替.enqueue(),它将同步执行请求。不需要
Interceptor,因为CSRF保护通常驻留在html<head>中;
如果字符串将在HTTP头中提供,则这将是另一回事。

相关文档:Interface Call<T>.

如果你不想使用runBlocking,那么你将不得不在IAuthApi接口中引入第二个返回Call<Auth>的端点。Call<Auth>将允许您在其上运行execute()函数以同步(阻塞)方式运行请求。

调用接口文档

下面使用Call.execute:

class AuthInterceptor(val authApi: IAuthService) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val freshCrsf = authApi.getAuthCall().execute().let { authResponse ->
if(authResponse.isSuccessful) {
authResponse.body().freshCrsf
} else {
// TODO handle error for example you can read authResponse.errorBody()
// and do something based on it
}
}
// ... add freshCsrf to form body
return chain.proceed(request)
}
}
// Retrofit service
interface IAuthApi {
@GET("/auth")
fun getAuthCall(): Call<Auth>
@GET("/auth")
suspend fun getAuth(): Auth
}

我认为runBlocking在这种情况下真的不是一个坏的选择。作为文档状态用于桥暂停代码的阻塞。Main函数和测试对我来说是常见的用例。

interface ApiInterface {
@GET("user/list")
fun userListGet(): Call<UserPageResponse>
}

lifecycleScope.launch {
val response = apiInterface.userListGet().await()
}

相关内容

  • 没有找到相关文章