Flutter使用Dio请求API获取token为空该如何解决?
问题描述
我正在尝试通过Flutter的Dio库从我的API获取token,但获取到的token为空,相关实现代码如下:
Dio相关工具函数
import 'package:dio/dio.dart'; class DioHelper { static Dio dio; static init() { print('dioHelper Initialized'); dio = Dio( BaseOptions( baseUrl:'my api link', receiveDataWhenStatusError: true, )); } static Future<Response> getData ({ String url, Map<String,dynamic> query, String lang = 'en', String token, Map<String,dynamic> data, })async { dio.options.headers = { 'lang':'$lang', 'Content-Type':'application/json', 'Authorization' : '$token' }; return await dio.get( url, queryParameters: query ); } static Future<Response> postData ({ String url, Map<String,dynamic> query, Map<String,dynamic> data, String lang = 'ar', String token })async { dio.options.headers = { 'lang':'$lang', 'Content-Type':'application/json', 'Authorization' : '$token' }; return await dio.post( url, queryParameters: query, data: data, ); } static Future<Response> putData ({ String url, Map<String,dynamic> query, Map<String,dynamic> data, String lang = 'ar', String token })async { dio.options.headers = { 'lang':'$lang', 'Content-Type':'application/json', 'Authorization' : '$token' }; return await dio.put( url, queryParameters: query, data: data, ); } static Future<Response> deleteData ({ String url, String lang = 'ar', String token })async { dio.options.headers = { 'lang':'$lang', 'Content-Type':'application/json', 'Authorization' : '$token' }; return await dio.delete(url); } }
全局token存储
String token = '';
sharedPreferences相关工具函数
import 'package:shared_preferences/shared_preferences.dart'; class CacheHelper { static SharedPreferences sharedPreferences; static init () async { sharedPreferences = await SharedPreferences.getInstance(); } static dynamic getData(String key, ){ return sharedPreferences.get(key); } static Future<bool> saveData({ String key, dynamic value})async{ if(value is String) return await sharedPreferences.setString(key, value); if(value is int) return await sharedPreferences.setInt(key, value); if(value is bool) return await sharedPreferences.setBool(key, value); return await sharedPreferences.setDouble(key, value); } static Future<bool> removeData (String key)async{ return await sharedPreferences.remove(key); } }
token调用逻辑
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); Bloc.observer = MyBlocObserver(); await DioHelper.init(); await CacheHelper.init(); token = CacheHelper.getData('token'); var IsLogin = CacheHelper.getData( 'IsLogin'); var IsBoarding = CacheHelper.getData( 'IsBoarding'); print(IsLogin); print(IsBoarding); print(token); var widget; if (IsBoarding != null) { if (token == null) { widget = ShopingScreen(); } else { widget = Login_Screen(); } } else { widget = BordScreen(); } }
我已经尝试过清空手机数据、重构代码、多次重启设备均无法解决,以下是可行的解决方案:
解决方案
- 修正Authorization请求头格式
绝大多数后端接口的Authorization请求头要求携带Bearer前缀,你当前直接拼接token的写法不符合规范,修改DioHelper中所有headers的Authorization字段为:
- 修正Authorization请求头格式
'Authorization' : token != null ? 'Bearer $token' : null,
如果你的后端自定义了前缀,按照后端要求替换Bearer即可。
- 处理token空值异常
你定义的全局token是不可空的String类型,但CacheHelper.getData返回的是dynamic类型,本地没有存储token时会返回null,直接赋值会触发空安全异常。修改赋值逻辑:
- 处理token空值异常
token = CacheHelper.getData('token') ?? '';
也可以将全局token定义为可空类型String? token;避免类型异常。
- 检查登录逻辑的token存储步骤
确认你调用登录接口获取到token后,确实调用了CacheHelper.saveData方法持久化存储:
- 检查登录逻辑的token存储步骤
// 登录接口请求成功后的示例逻辑 String responseToken = response.data['token']; await CacheHelper.saveData(key: 'token', value: responseToken); // 同时赋值给全局token token = responseToken;
同时检查接口返回的token字段名是否和你取值的字段名一致,避免把access_token错写为token的低级错误。
- 修正路由跳转逻辑
你当前的路由判断逻辑完全写反了:token不为空代表用户已经登录,应该直接跳首页,token为空才需要跳登录页,修改逻辑:
- 修正路由跳转逻辑
if (IsBoarding != null) { if (token != null && token.isNotEmpty) { // 有token跳首页 widget = ShopingScreen(); } else { // 无token跳登录页 widget = Login_Screen(); } }
- 优化DioHelper的token传递逻辑
你当前DioHelper的每个请求方法都需要手动传入token,调用时如果漏传就会导致请求头token为空。可以直接在DioHelper中读取全局token,不需要每次传参:
- 优化DioHelper的token传递逻辑
// 修改headers的取值逻辑,直接读全局token dio.options.headers = { 'lang':'$lang', 'Content-Type':'application/json', 'Authorization' : token.isNotEmpty ? 'Bearer $token' : null, };
内容的提问来源于stack exchange,提问作者Ahmed Ragab
相关产品推荐
相关产品推荐

