Android開発 - RxJavaを使ったネットワークリクエスト:トークンの再取得と再実行

前書き

皆さん、こんにちは!
久しぶりの投稿です。
今日は、RxJavaを使ったネットワークリクエスト(例:OkHttp + Retrofit)で、
トークンの再取得と同じ接続の再リクエストを解決する方法を共有します。
この問題は、多くの接続が必要なアプリでよく見られます。
サーバーにリクエストを送る際、
ユーザーの正当性を確保するために、
通常はトークン機構を使用してログインやAPIアクセスの権限を検証します。
トークンには有効期限があり、
良好なユーザー体験を提供するために、
特定のネットワークリクエスト中にトークンが期限切れになったことに気づかない場合でも、
より完全なプロセスを実現する必要があります。

関連知識


この記事では、以下の関連知識を使用しますが、
主にトークンの再取得とネットワーク接続の再接続のプロセスを共有することに焦点を当てているため、
詳細には触れません。興味がある方は調べるか、私にメッセージを送ってください:

  • ジェネリック
  • Kotlin拡張
  • Kotlin関数型
  • RxJava
  • Retrofit
  • Okhttp
考え方


通常、トークン機構を持つAPIリクエストをアプリケーションに統合する際、
適切な処理を行わないと、実行フローは以下のようになる可能性があります:

アプリネットワークリクエスト -> トークン期限切れ -> サーバーがアクセス期限切れを返す -> アプリがエラーに応じた処理を行う


このような場合、
エラー処理を行っているにもかかわらず、
トークンが期限切れになるたびに、
エラー処理(例:ユーザーにトークンが期限切れであることを通知)が発生します。
一度や二度なら偶発的な状況と見なされるかもしれませんが、
何度も繰り返されると、
ユーザーはアプリに問題があると感じ、
スムーズに実行できないと考え、
ユーザー体験が低下し、
さらなる問題を引き起こす可能性があります。

したがって、
以下のようなフローを実現し、
トークンを再取得した後、
元のネットワーク接続を再実行できるようにしたいと考えています:

アプリネットワークリクエスト -> トークン期限切れ -> サーバーがアクセス期限切れを返す -> トークン再取得プロセスを実行 -> アプリが同じネットワークリクエストを再実行


実際の開発

この記事では、主にRxJavaのオペレーターを使用してネットワークリクエストを行い、
RetrofitをラップしてOkHttpを適用してネットワークAPIをリクエストする方法を共有します:


RxJavaを使用してネットワークリクエストを操作する場合、
通常はRxオペレーターを使用して制御します。
ここでは、
Observableを使用しています。上記のコードでは:

repo.getPaymentData(paymentRequest)

返される結果はObservableです。
以前述べた方法に従うと、
最初の状況が発生する可能性があります。
つまり、ネットワークリクエスト後にトークンが無効になり、
エラー処理のみが行われ、トークンが再取得されても、
APIが再リクエストされません。

この問題を解決するために、
RxJavaを使用して実行中にトークンを再取得し、
新しいトークンを使用して元のAPIに再接続する方法を研究し始めました。
そのために、
この機能を実現するためのKotlinの拡張関数(extension function)を作成しました:

コード解説


1. この拡張機能を実際に適用すると、次のようになります:

使用は非常に簡単で、
トークンを再取得する必要がある場所にこの拡張関数を追加するだけです。
トークンを再取得する必要がない場所では、従来の方法で実行を続けます。
この拡張関数の応用は非常に柔軟で、
以下のコードを追加するだけです:

.retryNoKeyWhenError(resetRequest = {                       
     repo.getPaymentData(resetRequestToken(paymentRequest))})

2. 拡張した関数を個別に見てみましょう

私はflapmapを使用してObserable内のデータを解析しました。
また、これは接続リクエストであるため、通常サーバーは固定の形式で結果を返します。
ここでリクエスト結果の状態を解析し、
成功の場合は元のレスポンス全体をobserverに返します。
エラーの場合は、実際のニーズに応じて処理方法を記述します。例えば:

次のような状況に遭遇した場合
(ここでは独自に定義したenumクラスで、主に署名やトークンの期限切れの状況です。ここは自由に定義できます)

 State.FAIL_SIGNATURE_ERROR.value
 State.FAIL_SIGNATURE_EXPIRED.value
 State.FAIL_KEY_TOKEN_EXPIRED.value

トークンを再取得するAPIを実行し、必要なデータを保存した後、対応するデータを返し、元のエラー状況をobserverに返します。

3. この時点で、retryWhenを使用します

前にエラー状況を返したため、
retryWhenがトリガーされます。
ここでは、retry回数のObserableと何秒後に再試行するかを定義しました。
前のinputのIntに基づいて、失敗した場合に何秒後に再試行するかを判断します。

そして最も重要なのは、前に使用した関数タイプが、
ここで重要な役割を果たすことです。なぜなら、リクエストが失敗した後に、
実行する予定のメソッドがここに記述されるからです:

resetRequest.invoke().delay(delayInSeconds, TimeUnit.SECONDS)


ここで定義した拡張の戻り値の型はObservable < T >です。
そのため、元のサブスクリプションに再接続できるので、非常に便利だと思います。
参考にしてください。

最後に、
他の状況に応じて特定のエラー定数と処理フローを定義し、
この拡張関数に対応する処理ロジックを追加することができます。
どんな状況に遭遇しても、
事前に対応するエラー定数と処理フローを定義しておけば、
この拡張関数は対応する処理を実行するのに役立ちます。
この関数を自分のニーズに合わせて拡張し、
アプリケーションシナリオにより適応させることができます。

You might also enjoy