You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
  }
}

我已经尝试过清空手机数据、重构代码、多次重启设备均无法解决,以下是可行的解决方案:


解决方案
    1. 修正Authorization请求头格式
      绝大多数后端接口的Authorization请求头要求携带Bearer前缀,你当前直接拼接token的写法不符合规范,修改DioHelper中所有headers的Authorization字段为:
'Authorization' : token != null ? 'Bearer $token' : null,

如果你的后端自定义了前缀,按照后端要求替换Bearer即可。

    1. 处理token空值异常
      你定义的全局token是不可空的String类型,但CacheHelper.getData返回的是dynamic类型,本地没有存储token时会返回null,直接赋值会触发空安全异常。修改赋值逻辑:
token = CacheHelper.getData('token') ?? '';

也可以将全局token定义为可空类型String? token;避免类型异常。

    1. 检查登录逻辑的token存储步骤
      确认你调用登录接口获取到token后,确实调用了CacheHelper.saveData方法持久化存储:
// 登录接口请求成功后的示例逻辑
String responseToken = response.data['token'];
await CacheHelper.saveData(key: 'token', value: responseToken);
// 同时赋值给全局token
token = responseToken;

同时检查接口返回的token字段名是否和你取值的字段名一致,避免把access_token错写为token的低级错误。

    1. 修正路由跳转逻辑
      你当前的路由判断逻辑完全写反了:token不为空代表用户已经登录,应该直接跳首页,token为空才需要跳登录页,修改逻辑:
if (IsBoarding != null) {
  if (token != null && token.isNotEmpty) {
    // 有token跳首页
    widget = ShopingScreen();
  } else {
    // 无token跳登录页
    widget = Login_Screen();
  }
}
    1. 优化DioHelper的token传递逻辑
      你当前DioHelper的每个请求方法都需要手动传入token,调用时如果漏传就会导致请求头token为空。可以直接在DioHelper中读取全局token,不需要每次传参:
// 修改headers的取值逻辑,直接读全局token
dio.options.headers =
{
  'lang':'$lang',
  'Content-Type':'application/json',
  'Authorization' : token.isNotEmpty ? 'Bearer $token' : null,
};

内容的提问来源于stack exchange,提问作者Ahmed Ragab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 02:09:04