Как предотвратить параллельные запросы токенов обновления при использовании аутентификатора Retrofit/OkHttp? ⇐ Android
Как предотвратить параллельные запросы токенов обновления при использовании аутентификатора Retrofit/OkHttp?
Я только что наткнулся на проблему, когда я начал отправлять слишком параллельные запросы токенов обновления на встроенный сервер, который я построил, что вызвало проблемы с параллелизмом, когда возникает состояние гонки, в котором все эти параллельные запросы запрашивают и обновляют разные токены обновления на в то же время.
Единственное решение, которое я придумал, — это использовать StateFlow, Channel и сопрограмму ввода-вывода с незаданной областью для наблюдения за состоянием обновления, чтобы только первый запрос токена обновления был успешным, а пока он обновляется, другие параллельные запросы блокируются при наблюдении. пока они не получат сигнал от первого запроса токена обновления на использование нового токена.
Это работает, но я новичок в Kotlin и его API-интерфейсах сопрограмм, и это выглядит хаотично, я не могу с этим поделать, но думаю, что определенно есть более разумный способ подойти к этому.
класс MyAuthenticator @Inject конструктор( частный вал обновитьTokenUseCase: RefreshTokenUseCase, частный вал SharedPrefs: SharedPreferences ) : Аутентификатор { частный val isRefreshingToken = MutableStateFlow (false) частный вал newRequest = Channel() переопределить забаву аутентификации (маршрут: Маршрут?, ответ: Ответ): Запрос? { // логика для обработки блокировки параллельных запросов токена обновления, чтобы дождаться первого запроса токена обновления, чтобы использовать его вместо бесполезных вызовов API: если (isRefreshingToken.value) { CoroutineScope(Dispatchers.IO).launch { isRefreshingToken.collect { isRefreshingToken -> если (!isRefreshingToken) { val newToken =sharedPrefs.getToken().orEmpty() val req = response.request.newBuilder() .header("Авторизация", "Носитель $newToken") .строить() newRequest.send(требуется) } } } return runBlocking(Dispatcher.IO) { новыйRequest.receive() } } isRefreshingToken.value = true // логика для обработки обновления токена runBlocking(Dispatchers.IO) { обновитьTokenUseCase() // внутренне вызывает API токена обновления, а затем сохраняет токен в общих настройках }.let { результат -> isRefreshingToken.value = ложь вернуть, если (result.isSuccess) { val newToken =sharedPrefs.getToken().orEmpty() ответ.запрос.newBuilder() .header("Авторизация", "Носитель $newToken") .строить() } еще { // логика обработки сбоя (выход из системы и т. д.) нулевой } } } } Я обыскал весь стек и нашел много предложенных решений, но ни одно из них на самом деле не сработало, половина из которых предлагала использовать синхронизацию, чтобы заставить параллель запускаться упорядоченным образом, что по-прежнему расточительно вызывает API для обновлять токен слишком много раз.
Я только что наткнулся на проблему, когда я начал отправлять слишком параллельные запросы токенов обновления на встроенный сервер, который я построил, что вызвало проблемы с параллелизмом, когда возникает состояние гонки, в котором все эти параллельные запросы запрашивают и обновляют разные токены обновления на в то же время.
Единственное решение, которое я придумал, — это использовать StateFlow, Channel и сопрограмму ввода-вывода с незаданной областью для наблюдения за состоянием обновления, чтобы только первый запрос токена обновления был успешным, а пока он обновляется, другие параллельные запросы блокируются при наблюдении. пока они не получат сигнал от первого запроса токена обновления на использование нового токена.
Это работает, но я новичок в Kotlin и его API-интерфейсах сопрограмм, и это выглядит хаотично, я не могу с этим поделать, но думаю, что определенно есть более разумный способ подойти к этому.
класс MyAuthenticator @Inject конструктор( частный вал обновитьTokenUseCase: RefreshTokenUseCase, частный вал SharedPrefs: SharedPreferences ) : Аутентификатор { частный val isRefreshingToken = MutableStateFlow (false) частный вал newRequest = Channel() переопределить забаву аутентификации (маршрут: Маршрут?, ответ: Ответ): Запрос? { // логика для обработки блокировки параллельных запросов токена обновления, чтобы дождаться первого запроса токена обновления, чтобы использовать его вместо бесполезных вызовов API: если (isRefreshingToken.value) { CoroutineScope(Dispatchers.IO).launch { isRefreshingToken.collect { isRefreshingToken -> если (!isRefreshingToken) { val newToken =sharedPrefs.getToken().orEmpty() val req = response.request.newBuilder() .header("Авторизация", "Носитель $newToken") .строить() newRequest.send(требуется) } } } return runBlocking(Dispatcher.IO) { новыйRequest.receive() } } isRefreshingToken.value = true // логика для обработки обновления токена runBlocking(Dispatchers.IO) { обновитьTokenUseCase() // внутренне вызывает API токена обновления, а затем сохраняет токен в общих настройках }.let { результат -> isRefreshingToken.value = ложь вернуть, если (result.isSuccess) { val newToken =sharedPrefs.getToken().orEmpty() ответ.запрос.newBuilder() .header("Авторизация", "Носитель $newToken") .строить() } еще { // логика обработки сбоя (выход из системы и т. д.) нулевой } } } } Я обыскал весь стек и нашел много предложенных решений, но ни одно из них на самом деле не сработало, половина из которых предлагала использовать синхронизацию, чтобы заставить параллель запускаться упорядоченным образом, что по-прежнему расточительно вызывает API для обновлять токен слишком много раз.
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Как изменить URL-адрес запроса с помощью Retrofit и Okhttp (воссоздание Retrofit2.Call)
Anonymous » » в форуме Android - 0 Ответы
- 31 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как сгенерировать QR-код аутентификатора с помощью Blazor .NET 8 в компоненте бритвы
Anonymous » » в форуме C# - 0 Ответы
- 16 Просмотры
-
Последнее сообщение Anonymous
-