我从颤抖开始,我制作了一个简单的应用程序,该应用程序使用REST API管理登录屏幕。
我正在使用http包和http_interceptor包来拦截并发送标头中的令牌。
问题是...我可以使用拦截器捕获错误,而没有任何问题。但是,有什么方法可以使用全局小吃栏,从我的拦截器类中可以“通知”并将用户重定向到显示应用程序中任何错误的登录屏幕,例如,当令牌无效时?
这是我的拦截器类:
class ApiInterceptor with ChangeNotifier implements InterceptorContract {
final storage = new FlutterSecureStorage();
@override
Future<RequestData> interceptRequest({RequestData data}) async {
[...] // here is the request interceptor
return data;
}
// The response interceptor:
@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
final decodedResponse = json.decode(data.body);
if (data.statusCode >= 400) {
throw HttpException(decodedResponse['error']);
// here i want to send the notification to a snackBar
// then, i want to redirect the user to the login screen
}
return data;
}
}
[UPDATE I]
这里是我使用的提供者。在此提供程序中,我使用拦截器。
import 'dart:convert';
import 'package:cadsanjuan_movil/models/http_exception.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:http/http.dart';
import 'package:http_interceptor/http_interceptor.dart';
import '../config/http_interceptor.dart';
import '../config/.env.dart' as config;
class Auth with ChangeNotifier {
String _endpoint = 'auth';
final storage = new FlutterSecureStorage();
// Http Interceptor
Client http = HttpClientWithInterceptor.build(interceptors: [
ApiInterceptor(),
]);
Future singup(String email, String password) async {
final url = "${config.apiBaseUrl}/$_endpoint/signin";
try {
final response = await http.post(url,
body: json.encode({'email': email, 'password': password}));
final decodedResponse = json.decode(response.body);
/* if (response.statusCode >= 400) {
throw HttpException(decodedResponse['error']);
} */
await storage.write(key: 'token', value: decodedResponse['token']);
await storage.write(key: 'user', value: decodedResponse['user']);
await storage.write(key: 'email', value: decodedResponse['email']);
await storage.write(
key: 'employeeId', value: decodedResponse['employeeId'].toString());
//notifyListeners();
} catch (error) {
throw error;
}
}
}
这些提供者在我的main.dart中使用MultipleProvider
小部件被调用:
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: ApiInterceptor(),
),
ChangeNotifierProvider.value(
value: Auth(),
),
ChangeNotifierProvider.value(
value: TurnActive(),
),
],
child: MaterialApp(
.
.
.
[UPDATE II]
这里main.dart
已更新...仍然无法正常工作。
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
final storage = new FlutterSecureStorage();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'CAD App',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: Scaffold(
body: MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: ApiInterceptor(context: context),
),
ChangeNotifierProvider.value(
value: Auth(context: context),
),
ChangeNotifierProvider.value(
value: TurnActive(context: context),
),
],
child: FutureBuilder(
future: storage.read(key: "token"),
builder: (context, storedKey) {
if (!storedKey.hasData) {
return LoadingData(text: 'Por favor espere...');
} else {
return storedKey.data == null
? LoginPage()
: InitialLoadingPage();
}
},
),
),
),
);
}
}
在我的拦截器上:
.
.
.
@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
final decodedResponse = json.decode(data.body);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(decodedResponse['error']),
));
.
.
.
错误是:Scaffold.of() called with a context that does not contain a Scaffold.
[由于Dart的工作原理,抓住BuildContext
有点可惜,但100%的可能性。我将指导您完成以下步骤:
BuildContext
中需要ApiInterceptor
当前正在声明ApiInterceptor
类,而没有任何输入变量,因此您需要在顶部的类中添加以下内容。
ApiInterceptor({
@required this.context,
}) : assert(context != null);
final BuildContext context;
现在,每次在代码库中访问您的类时,IDE都会通知您缺少变量。
BuildContext
中的Auth
您很遗憾必须与Auth
提供者做同样的事情。我将为您保留与上一步相同的独白,因为它们几乎是相同的过程。以下是您必须添加到Auth
类的开头的内容。
Auth({
@required this.context,
}) : assert(context != null);
final BuildContext context;
步骤3:在每种情况下都通过BuildContext
您可能会发现,您的IDE会为您完成大部分工作!以下是您所有课程的完整代码。
class ApiInterceptor with ChangeNotifier implements InterceptorContract {
ApiInterceptor({
@required this.context,
}) : assert(context != null);
final BuildContext context;
final storage = new FlutterSecureStorage();
@override
Future<RequestData> interceptRequest({RequestData data}) async {
[...] // here is the request interceptor
return data;
}
// The response interceptor:
@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
final decodedResponse = json.decode(data.body);
if (data.statusCode >= 400) {
throw HttpException(decodedResponse['error']);
// here i want to send the notification to a snackBar
// then, i want to redirect the user to the login screen
}
return data;
}
}
class Auth with ChangeNotifier {
Auth({
@required this.context,
}) : assert(context != null);
final BuildContext context;
String _endpoint = 'auth';
final storage = new FlutterSecureStorage();
Future singup(String email, String password) async {
// Http Interceptor
Client http = HttpClientWithInterceptor.build(interceptors: [
ApiInterceptor(context: context),
]);
final url = "${config.apiBaseUrl}/$_endpoint/signin";
try {
final response = await http.post(url,
body: json.encode({'email': email, 'password': password}));
final decodedResponse = json.decode(response.body);
/* if (response.statusCode >= 400) {
throw HttpException(decodedResponse['error']);
} */
await storage.write(key: 'token', value: decodedResponse['token']);
await storage.write(key: 'user', value: decodedResponse['user']);
await storage.write(key: 'email', value: decodedResponse['email']);
await storage.write(
key: 'employeeId', value: decodedResponse['employeeId'].toString());
//notifyListeners();
} catch (error) {
throw error;
}
}
}
当然,您的main()
输出:
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: ApiInterceptor(context: context),
),
ChangeNotifierProvider.value(
value: Auth(context: context),
),
ChangeNotifierProvider.value(
value: TurnActive(),
),
],
child: /* CHILD!!! */,
);
}
我希望这会有所帮助,并使您的一天变得[[小更加轻松。