我正在构建一个Flutter应用程序,该应用程序使用Golang API来获取数据。如果JWT令牌无效,则API将返回未经授权的401。如果响应状态为401,如何在任何API调用上重定向到登录页面?
这是我的颤动代码:
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Provider.debugCheckInvalidValueType = null;
AppLanguage appLanguage = AppLanguage();
await appLanguage.fetchLocale();
runApp(MyApp(
appLanguage: appLanguage,
));
}
class MyApp extends StatelessWidget {
final AppLanguage appLanguage;
MyApp({this.appLanguage});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: providers,
child: MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
initialRoute: RoutePaths.Login,
onGenerateRoute: Router.generateRoute,
)
);
}
}
tables.dart
class Tables extends StatelessWidget {
const Tables({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BaseWidget<TablesModel>(
model: TablesModel(api: Provider.of(context, listen: false)),
onModelReady: (model) => model.fetchTables(),
builder: (context, model, child) => model.busy
? Center(
child: CircularProgressIndicator(),
)
: Expanded(
child: GridView.builder (
---
tables_model.dart
class TablesModel extends BaseModel {
Api _api;
TablesModel({@required Api api}) : _api = api;
List<Tbl> tables;
Future fetchTables() async {
setBusy(true);
tables = await _api.getTables();
setBusy(false);
}
@override
void dispose() {
print('Tables has been disposed!!');
super.dispose();
}
}
api.dart
Future<List<Tbl>> getTables() async {
var tables = List<Tbl>();
try {
var response = await http.get('$_baseUrl/tables/list');
var parsed = json.decode(response.body) as List<dynamic>;
if (parsed != null) {
for (var table in parsed) {
tables.add(Tbl.fromJson(table));
}
}
} catch (e) {print(e); return null;}
return tables;
}
答案 0 :(得分:2)
由于树中已经有MaterialApp
并已注册了命名路由,因此这就像添加一个调用以在获得响应的同时推送登录页面一样简单。
首先,您应该修改getTables
来检查response
的状态代码,该状态代码具有Response
对象的statusCode
属性,并显示以下代码块:
var response = await http.get('$_baseUrl/tables/list');
if(response.statusCode == 401) {
//Act on status of 401 here
}
现在,您可以检查响应的状态码为401的时间,您可以使用Navigator
导航到登录页面。 Navigator
需要BuildContext
,因此必须将其传递给getTables
函数。
这涉及将getTables
修改为:
Future<List<Tbl>> getTables(BuildContext context) async {
和fetchTables
需要类似的更改:
Future fetchTables(BuildContext context) async {
然后,在调用这些方法的位置,您将context
向下传递:
在Tables
model.fetchTables(context)
在TablesModel
Future fetchTables(BuildContext context) async {
setBusy(true);
tables = await _api.getTables(context);
setBusy(false);
}
最后在getTables
中,您使用传递的context
来使用Navigator
:
Future<List<Tbl>> getTables(BuildContext context) async {
var tables = List<Tbl>();
try {
var response = await http.get('$_baseUrl/tables/list');
//Check response status code
if(response.statusCode == 401) {
Navigator.of(context).pushNamed(RoutePaths.Login);//Navigator is used here to go to login only with 401 status code
return null;
}
var parsed = json.decode(response.body) as List<dynamic>;
if (parsed != null) {
for (var table in parsed) {
tables.add(Tbl.fromJson(table));
}
}
} catch (e) {print(e); return null;}
return tables;
}
如果愿意,您可以使用Navigator.of(context).pushNamed(RoutePaths.Login);
来代替Navigator.pushNamed(context, RoutePaths.Login);
,但是正如您可以在this answer上阅读的那样,它们在内部执行相同的操作。
现在,当状态码为401时,用户将被导航到登录屏幕。