Flutter API调用处理方案咨询:如何在封装函数中获取UserProvider的jwt
问题1:在封装的api函数中直接获取UserProvider的jwt
推荐使用服务定位器方案,无需依赖BuildContext即可全局获取UserProvider实例,操作步骤如下:
- 先在
pubspec.yaml中添加get_it依赖:
dependencies: get_it: ^7.6.0
- 在main函数执行
runApp前初始化全局服务定位器,注册UserProvider单例:
final getIt = GetIt.instance; void setupLocator() { getIt.registerSingleton<UserProvider>(UserProvider()); } void main() { setupLocator(); runApp(const MyApp()); }
- 在Provider组件中注册UserProvider时直接复用getIt中的单例,不要创建新实例:
ChangeNotifierProvider.value( value: getIt<UserProvider>(), child: ... )
- 最后在api函数中直接读取jwt即可,无需从Widget层传参:
var headers = { 'Content-Type': 'application/json', "Authorization": 'Bearer ${getIt<UserProvider>().jwt ?? ""}' };
问题2:API封装方案优化建议
你当前的封装思路和React技术栈中统一封装axios的思路一致,基础逻辑是合理的,但还有可优化的空间,更推荐的实现方案如下:
- 替换原生http包为
dio包,dio自带拦截器、请求取消、全局配置等能力,和你熟悉的axios用法高度重合,不需要手动封装大量通用逻辑 - 现有实现缺少的通用能力建议补齐:
- 响应状态码统一判断,比如401时自动跳转登录页、清空UserProvider存储的用户信息
- 响应数据自动反序列化,无需每次调用接口后手动转JSON
- 错误统一处理,网络错误、超时错误等通用异常统一提示,无需每个接口单独写catch逻辑
- 可选的请求Loading状态关联,方便页面统一控制Loading显隐
- 优化后的dio封装参考:
class HttpUtil { static final Dio _dio = Dio(BaseOptions( baseUrl: SERVER_URL, contentType: Headers.jsonContentType, connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10), )); // 初始化全局拦截器 static void initInterceptor() { _dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) { // 统一注入jwt final jwt = getIt<UserProvider>().jwt; if (jwt != null && jwt.isNotEmpty) { options.headers['Authorization'] = 'Bearer $jwt'; } return handler.next(options); }, onResponse: (response, handler) { // 统一提取业务层需要的返回数据 return handler.next(response); }, onError: (DioError e, handler) { // 统一处理错误 if (e.response?.statusCode == 401) { getIt<UserProvider>().setUser(id: null, name: null, email: null, role: null, jwt: null); // 这里可通过全局NavigatorKey跳转登录页 } return handler.next(e); } )); } // 通用请求方法 static Future request(String url, String method, {dynamic body, Map<String, dynamic>? extra}) async { try { final response = await _dio.request( getUrl(url, method, extra), data: body, options: Options(method: method), ); return response.data; } catch (e) { rethrow; } } // 快捷请求方法 static Future get(String url, {Map<String, dynamic>? params, Map<String, dynamic>? extra}) => request(url, 'GET', body: params, extra: extra); static Future post(String url, {dynamic data, Map<String, dynamic>? extra}) => request(url, 'POST', body: data, extra: extra); }
调用前在main函数初始化拦截器即可:
void main() { setupLocator(); HttpUtil.initInterceptor(); runApp(const MyApp()); }
后续接口调用直接使用HttpUtil.get()、HttpUtil.post()即可,不需要额外传jwt参数。
内容的提问来源于stack exchange,提问作者Bhuwan Adhikari
相关产品推荐
相关产品推荐

