RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1091102
Accepted
Andrew
Andrew
Asked:2020-03-05 20:05:10 +0000 UTC2020-03-05 20:05:10 +0000 UTC 2020-03-05 20:05:10 +0000 UTC

如何在拦截器android改造中取消请求?

  • 772

有这样一个拦截器:

class AuthToken(context: Context) : Interceptor {
    var cont = context
    override fun intercept(chain: Interceptor.Chain): Response {
        val sp = cont.getSharedPreferences("app_data", 0)
        val originalRequest:Request? = (if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
            updateToken(chain)
            null
        } else {
            chain.request()
                    .newBuilder()
                    .header("Content-type:", "application/json")
                    .header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                    .build()
        })


        if (originalRequest!=null){
            val response = chain.proceed(originalRequest)
            when (response.code) {
                401 -> {
                    updateToken(chain)
                }
                500 -> {
                    Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
                }
            }


            return response
        }else chain.proceed(originalRequest)

    }


    private fun updateToken(request: Interceptor.Chain) {
        val interceptor = HttpLoggingInterceptor()
        interceptor.level = HttpLoggingInterceptor.Level.BODY

        val dispatcher = Dispatcher()
        dispatcher.maxRequests = 1

        val client = OkHttpClient.Builder()
                .addInterceptor(interceptor)
                .connectTimeout(100, TimeUnit.SECONDS)
                .dispatcher(dispatcher)
                .readTimeout(100, TimeUnit.SECONDS).build()


        client.dispatcher.cancelAll()
        val retrofit = Retrofit.Builder()
                .baseUrl(BuildConfig.API_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        val api = retrofit.create(APIService::class.java)

        api.getNewToken(ReqAccessToken(cont.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!)).enqueue(object : Callback<ResNewTokens> {
            override fun onResponse(call: Call<ResNewTokens>, response: retrofit2.Response<ResNewTokens>) {
                if (response.isSuccessful) {
                    val editor = cont.getSharedPreferences("app_data", 0).edit()
                    editor.putString("access_token", Objects.requireNonNull<ResNewTokens>(response.body()).access_token).apply()
                    editor.putString("refresh_token", Objects.requireNonNull<ResNewTokens>(response.body()).refresh_token).apply()
                    editor.putLong("expires_in", response.body()!!.expires_in!!).apply()

                    makeNewCall(request)
                } else {
                    when (response.code()) {
                        401 -> {
                            Singleton.logOut(cont)
                        }

                        500 -> {
                            Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }

            override fun onFailure(call: Call<ResNewTokens>, t: Throwable) {

            }

        })
    }

    private fun makeNewCall(req: Interceptor.Chain): Request {
        return req.request()
                .newBuilder()
                .header("Content-type:", "application/json")
                .header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                .build()
    }
}

问题出在以下几行:

if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
            updateToken(chain)
            null
        }

我要解决的问题的本质是删除带有腐烂令牌的额外请求,该令牌肯定会返回 401 错误。为此,我将所有内容都包装在了 if 中,但无法正常实现,因为函数intercept必须以任何方式返回Response,而在这种情况下不会这样做。想使那个 null 被发送,但结果是歪曲的。您需要以某种方式取消为消息计划的请求,或者以某种方式解决此问题,但我不知道具体如何:(

更新:

以下是目前的成果:

override fun intercept(chain: Interceptor.Chain): Response {
        val sp = cont.getSharedPreferences("app_data", 0)
        val originalRequest = if (sp!!.getLong("expires_in", 0) - sp.getLong("time_delta", 0) - System.currentTimeMillis() / 1000 <= 60) {
            val interceptor = HttpLoggingInterceptor()
            interceptor.level = HttpLoggingInterceptor.Level.BODY

            val dispatcher = Dispatcher()
            dispatcher.maxRequests = 1


            val client = OkHttpClient.Builder()
                    .addInterceptor(interceptor)
                    .connectTimeout(100, TimeUnit.SECONDS)
                    .dispatcher(dispatcher)
                    .readTimeout(100, TimeUnit.SECONDS).build()


            client.dispatcher.cancelAll()
            val retrofit = Retrofit.Builder()
                    .baseUrl(BuildConfig.API_URL)
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build()
            val api = retrofit.create(APIService::class.java)
            synchronized(this) {
                when {
                    api.getNewToken(ReqAccessToken(cont.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!)).execute().isSuccessful -> {
                        val responseBody = api.getNewToken(ReqAccessToken(cont.getSharedPreferences("app_data", 0).getString("refresh_token", "")!!)).execute().body()
                        val editor = cont.getSharedPreferences("app_data", 0).edit()
                        editor.putString("access_token", Objects.requireNonNull<ResNewTokens>(responseBody).access_token).apply()
                        editor.putString("refresh_token", Objects.requireNonNull<ResNewTokens>(responseBody).refresh_token).apply()
                        editor.putLong("expires_in", responseBody!!.expires_in!!).apply()

                        chain.request()
                                .newBuilder()
                                .header("Content-type:", "application/json")
                                .header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                                .build()
                    }

                    else->{

                    }
                }
            }



        } else {
            chain.request()
                    .newBuilder()
                    .header("Content-type:", "application/json")
                    .header("Authorization", "Bearer " + cont.getSharedPreferences("app_data", 0).getString("access_token", "")!!)
                    .build()
        }


        val response = chain.proceed(originalRequest)
        when (response.code) {
            401 -> {
                //updateToken(chain)
            }
            500 -> {
                Toast.makeText(cont, cont.getString(R.string.server_error_500), Toast.LENGTH_SHORT).show()
            }
        }


        return response
    }

并val response = chain.proceed(originalRequest)说他们正在等待请求。然后我尝试在 if 中规定请求,但据我所知,它不可见。

android
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    ЮрийСПб
    2020-03-06T00:06:06Z2020-03-06T00:06:06Z

    你应该得到这样的结果:

    //network
    val logger = object : HttpLoggingInterceptor.Logger {
        override fun log(message: String) {
            Timber.tag("OkHttp").d(message)
        }
    }
    val loggingInterceptor = HttpLoggingInterceptor(logger)
        .apply {
            level = HttpLoggingInterceptor.Level.BODY
        }
    val okHttpClientCommon = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()
    
    val authRetrofit = Retrofit.Builder()
        .baseUrl(BuildConfig.API_IP + BuildConfig.API_URL)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .client(okHttpClientCommon)
        .build()
    val authApi = authRetrofit.create(AuthApi::class.java)
    
    val accessTokenInterceptor = object : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            //we need to set header in any case, as we need to receive JSON response
            //instead of redirect to `/login/ page
            val token = sessionRepository.getAccessToken() ?: ""
            val request =
                chain
                    .request()
                    .newBuilder()
                    .header(
                        ScpConstants.Api.HEADER_AUTHORIZATION,
                        ScpConstants.Api.HEADER_PART_BEARER + token
                    )
                    .build()
            return chain.proceed(request)
        }
    }
    
    val unauthAccessTokenInterceptor = object : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            if (tokenExpired()) updateAccessToken()
            val initialRequest = chain.request()
            val initialResponse = chain.proceed(initialRequest)
            if (initialResponse.code == HttpURLConnection.HTTP_UNAUTHORIZED && sessionRepository.getRefreshToken() != null) {
                updateAccessToken()
    
                //we need to close response to be able to start new request
                initialResponse.close()
                val authorizedRequest = initialRequest
                    .newBuilder()
                    .header(
                        ScpConstants.Api.HEADER_AUTHORIZATION,
                        ScpConstants.Api.HEADER_PART_BEARER + tokenResponse.accessToken
                    )
                    .build()
                return chain.proceed(authorizedRequest)
            } else {
                return initialResponse
            }
        }
    }
    
    val accessTokenOkHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .addInterceptor(accessTokenInterceptor)
        .addInterceptor(unauthAccessTokenInterceptor)
        .build()
    
    //user api
    val userRetrofit = Retrofit.Builder()
        .baseUrl(BuildConfig.API_IP + BuildConfig.API_URL + ScpConstants.Api.Endpoint.USER)
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .client(accessTokenOkHttpClient)
        .build()
    

    fun updateAccessToken() {
    
        val tokenResponse = authApi
            .getAccessTokenByRefreshTokenSync(
                Credentials.basic(
                    BuildConfig.CLIENT_ID,
                    BuildConfig.CLIENT_SECRET
                ),
                ScpConstants.Api.GRANT_TYPE_REFRESH_TOKEN,
                sessionRepository.getRefreshToken()!!
            )
            .execute()
            .body()
            ?: throw NullPointerException("Body is null while get accessToken by refreshToken!")
        sessionRepository.setAccessToken(tokenResponse.accessToken)
    
    }
    
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5