Flutter如何在未经授权的情况下重定向到登录

EmJ*_*iEn 8 flutter

如果令牌已在 Flutter 中过期,我正在尝试重定向到登录

尝试获取帖子:

body: new Container(
    padding: new EdgeInsets.only(bottom: 8.0),
    color: Color(0xff2c3e4e),
    child: FutureBuilder<List<Post>>(
        future: api.getposts(),
        builder: (context, snapshot) {
            // doing stuff with response
        }
    )
)
Run Code Online (Sandbox Code Playgroud)

getposts 并捕获错误:

Future<List<Post>> getposts() async {
    url = 'url';
    var response = await http.get(url,
        headers: {HttpHeaders.authorizationHeader: 'bearer ' + token},
    );
    //part I can't understand how to get to work, how do I push? This gives error about context not being defined.
    if (response.body.toString().contains('Token is Expired')) {
        Navigator.push(
            context,
            MaterialPageRoute(
                builder: (context) =>
                    LoginScreen()),
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

所以问题是,在这种情况下我如何正确使用 Navigator 并且我可以重定向回 l​​oginScreen 以防令牌已过期并需要更新?就像代码示例中的注释中提到的那样,上下文给了我“未定义”。

这甚至可能是我做的方式还是我只是处理整个检查完全错误?

Tru*_*inh 6

代码应该具有单一职责。你的getPost方法同时做两件事。您应该中断此函数,以便它成功获取帖子或抛出异常,并且其调用者将处理异常。顺便说一句,它的调用者必须在build方法内,因为只有build方法有BuildContext context,如下所示:

      if (response.body.toString().contains('Token is Expired')) {
        throw new Exception("Token is Expired") // you may want to implement different exception class
      }
Run Code Online (Sandbox Code Playgroud)
      body: new Container(
        padding: new EdgeInsets.only(bottom: 8.0),
        color: Color(0xff2c3e4e),
        child: FutureBuilder<List<Post>>(
            future: api.getposts(),
            builder: (context, snapshot) {
              if (snapshot.hasError) {
                // you might want to handle different exception, such as token expires, no network, server down, etc.
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => LoginScreen()),
                );
                return Container(); // return empty widget
              }
              if (snapshot.hasData) {
                // do somthing with data
                return Text('Some data here');
              }
              // has no data
              return Text("Loading...");

            }),
      ),
Run Code Online (Sandbox Code Playgroud)

更新

感谢@TruongSinh,我明白了。

按照他的示例,找出了有效的构建导航器方法:

if (snapshot.hasError) {

              @override
              void run() {
                scheduleMicrotask(() {

                  Navigator.pushReplacement(
                    context,
                    MaterialPageRoute(builder: (context) => LoginScreen()),
                  );
                });
              }
              run();
}
Run Code Online (Sandbox Code Playgroud)


Ced*_*Ced 5

我这样做是为了StreamBuilder对变化做出反应,并且当我们还不知道用户是否已连接时能够显示加载屏幕。

StreamBuilder authGuard = StreamBuilder(
  stream: Auth.authState$,
  builder: (context, snapshot) {
    switch (snapshot.data) {
      case AuthState.PENDING:
        return LoadingScreen();
      case AuthState.UNAUTHENTICATED:
        return SignInScreen();
      case AuthState.AUTHENTICATED:
        return HomeScreen();
      default:
        return LoadingScreen();
    }
  },
);
Run Code Online (Sandbox Code Playgroud)

因此它会根据 AuthState 改变屏幕:

return MaterialApp(
  // ...
  home: authGuard,
);
Run Code Online (Sandbox Code Playgroud)