如何等待悬浮功能的结果?

发布于 2025-02-12 17:45:55 字数 1928 浏览 0 评论 0原文

我需要将freshcsrf字符串添加到每个请求中。使用okhttpclient带有authinterceptor。问题是如何将请求发送到Interceptor中以获取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
}

我尝试使用coroutine,但也失败了,因为等不及结果。 async/等待案例以错误

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说明相混淆的

示例之一

它设计为桥梁定期阻止代码 以悬浮方式编写,用于主要功能测试

在一侧,改造接口正在暂停,我需要等待网络结果,以便继续创建其他请求(桥梁 - 确定)。但是在另一边,它不是主要功能或测试。而且,许多教程和文章都说必须避免生产代码中的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)
    }

I need to add freshCsrf string to each request into form body. Uses OkHttpClient with AuthInterceptor. The problem is how to send request inside interceptor in order to get the freshCsrf string?

In code below occurs error

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
}

I try to use coroutine, but also failed because can't wait result. One of example with async/await case ended with error

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)
    }

Update 1

I confused with runBlocking description

It is designed to bridge regular blocking code to libraries that are
written in suspending style, to be used in main functions and in
tests.

In one side, retrofit interface is suspending and I need to wait network result in order to continue creating other request (bridge - ok). But in the other side, it isn't main function or test. And many tutorials and articles tell that must to avoid runBlocking in production code. Can you explain it?

    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)
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千纸鹤带着心事 2025-02-19 17:45:55

如果您不想使用runblocking,则必须介绍返回call< auth>的第二个端点。 呼叫< 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在这种情况下,实际上并不是一个不好的选择。作为文档状态,它用于将悬挂代码桥接到阻止范围。对我来说,主要功能和测试是常见用例。

If you don't want to use runBlocking then you will have to introduce second endpoint that returns Call<Auth> in the IAuthApi interface. Call<Auth> will allow you to run execute() function on it to run a request in synchronous (blocking) way.

Call interface documentation

Below how it can look like using 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
}

I think runBlocking in this case is not a bad option really. As documentation state it's used to bridge suspending code to the blocking one. Main function and tests for me are common use cases.

墨离汐 2025-02-19 17:45:55

使用.execute()而不是.enqueue(),它将同步执行请求。
interceptor不需要,因为CSRF保护通常位于HMTL &lt; head&gt;;

如果将字符串放在HTTP标题中,这将是其他事情。

相关文档:代码>

Use .execute() instead of .enqueue() and it will perform the request synchronously.
Interceptor is not required, as CSRF protection usually resides in the HMTL <head>;
this would be something else, if the string would be served in the HTTP headers.

The relevent documentation: Interface Call<T>.

顾铮苏瑾 2025-02-19 17:45:55
interface ApiInterface {
@GET("user/list")
fun userListGet(): Call<UserPageResponse>
}


lifecycleScope.launch {
val response = apiInterface.userListGet().await()
}
interface ApiInterface {
@GET("user/list")
fun userListGet(): Call<UserPageResponse>
}


lifecycleScope.launch {
val response = apiInterface.userListGet().await()
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文