如何在 RetryPolicy 拦截器中传递 BuildContext

huangapple go评论62阅读模式
英文:

Hot to pass BuildContext inside the RetryPolicy Interceptor

问题

以下是您要翻译的代码部分:

I need to create an interceptor that whenever my API response is 401, I need to refresh the token with the refreshToken. And if something goes wrong, I need to redirect the user to the LoginPage.

But I'm having some difficulties on passing the BuildContext inside the refreshToken method... I'm using the http_interceptor dependency.

class AuthedApiClient {
  http.Client client = InterceptedClient.build(
    interceptors: [AuthorizationInterceptor()],
    requestTimeout: const Duration(seconds: 10),
  );

  static Future<void> refreshToken(BuildContext context) async {
    LoginService loginService = LoginService();
    try {
      loginService.refreshLogin();
    } catch (e) {
      if (e is RefreshTokenException) {
        Fluttertoast.showToast(
          msg: e.message,
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.BOTTOM,
          timeInSecForIosWeb: 1,
          textColor: Colors.black,
          backgroundColor: ThemeColors.errorToastMessage,
          fontSize: 12.0,
        );
      }
      Navigator.pushReplacementNamed(context, '/');
    }
  }
}
class AuthorizationInterceptor implements InterceptorContract {
  Logger logger = Logger();

  @override
  Future<RequestData> interceptRequest({required RequestData data}) async {
    logger.v(
        "Requisição para: ${data.baseUrl}\nCabeçalhos: ${data.headers}\nCorpo: ${data.body}");
    try {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      var token = prefs.getString('token');
      data.headers.clear();
      data.headers['Authorization'] = 'Bearer ${token!}';
      data.headers['Content-type'] = 'application/json';
      data.headers['Client'] = 'CustomerApp';
    } catch (e) {
      logger.e(e);
    }
    return data;
  }

  @override
  Future<ResponseData> interceptResponse({required ResponseData data}) async {
    return data;
  }
}

class ExpiredTokenRetryPolicy extends RetryPolicy {
  @override
  Future<bool> shouldAttemptRetryOnResponse(ResponseData response) async {
    if (response.statusCode == 401) {
      await AuthedApiClient.refreshToken(); //I need to somehow pass the context to this guy here...
      return true;
    }
    return false;
  }
}

希望这对您有所帮助!

英文:

I need to create an interceptor that whenever my API response is 401, I need to refresh the token with the refreshToken. And if something goes wrong, I need to redirect the user to the LoginPage.

But I'm having some difficulties on passing the BuildContext inside the refreshToken method... I'm using the http_interceptor dependency.

class AuthedApiClient {
http.Client client = InterceptedClient.build(
interceptors: [AuthorizationInterceptor()],
requestTimeout: const Duration(seconds: 10),
);
static Future&lt;void&gt; refreshToken(BuildContext context) async {
LoginService loginService = LoginService();
try {
loginService.refreshLogin();
} catch (e) {
if (e is RefreshTokenException) {
Fluttertoast.showToast(
msg: e.message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 1,
textColor: Colors.black,
backgroundColor: ThemeColors.errorToastMessage,
fontSize: 12.0,
);
}
Navigator.pushReplacementNamed(context, &#39;/&#39;);
}
}
}
class AuthorizationInterceptor implements InterceptorContract {
Logger logger = Logger();
@override
Future&lt;RequestData&gt; interceptRequest({required RequestData data}) async {
logger.v(
&quot;Requisi&#231;&#227;o para: ${data.baseUrl}\nCabe&#231;alhos: ${data.headers}\nCorpo: ${data.body}&quot;);
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var token = prefs.getString(&#39;token&#39;);
data.headers.clear();
data.headers[&#39;Authorization&#39;] = &#39;Bearer ${token!}&#39;;
data.headers[&#39;Content-type&#39;] = &#39;application/json&#39;;
data.headers[&#39;Client&#39;] = &#39;CustomerApp&#39;;
} catch (e) {
logger.e(e);
}
return data;
}
@override
Future&lt;ResponseData&gt; interceptResponse({required ResponseData data}) async {
return data;
}
}
class ExpiredTokenRetryPolicy extends RetryPolicy {
@override
Future&lt;bool&gt; shouldAttemptRetryOnResponse(ResponseData response) async {
if (response.statusCode == 401) {
await AuthedApiClient
.refreshToken(); //I need to somehow pass the context to this guy here...
return true;
}
return false;
}
}

答案1

得分: 2

有时,我们可能无法在应用程序的任何地方获取当前的context,在这种情况下,我们应该考虑使用全局上下文。

要使用全局上下文,我们需要执行以下操作:

创建一个类,如下所示:

class AppSettings {
  static GlobalKey<NavigatorState> navigatorState = GlobalKey<NavigatorState>();
}

现在,在你的MaterialApp中,将navigatorKey设置为:

navigatorKey: AppSettings.navigatorState,

现在,在你的refreshToken函数中获取BuildContext,你不需要将context作为参数定义。

将这个:

Navigator.pushReplacementNamed(context, '/');

替换为:

Navigator.pushReplacementNamed(AppSettings.navigatorState.currentContext!, '/');

完成。

英文:

Sometimes we might not be able to get current context in our app wherever we need, in those cases, We should consider using Global Context.

For using Global Context, What we need to do is:

create a class like this:

class AppSettings {
static GlobalKey&lt;NavigatorState&gt; navigatorState = GlobalKey&lt;NavigatorState&gt;();
}

Now, inside your MaterialApp give navigatorKey as:

navigatorKey: AppSettings.navigatorState,

Now, to get the BuildContext inside your refreshToken function, you don't need to define context as parameter.

Replace this Navigator.pushReplacementNamed(context, &#39;/&#39;); by:

Navigator.pushReplacementNamed(AppSettings.navigatorState.currentContext!, &#39;/&#39;);

And you're done.

huangapple
  • 本文由 发表于 2023年2月24日 03:49:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75549667.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定