Dio Interceptor 无法处理同一回调中的第一个请求,仅处理后续调用

Posted

技术标签:

【中文标题】Dio Interceptor 无法处理同一回调中的第一个请求,仅处理后续调用【英文标题】:Dio Interceptor not working on first request in same callback, only subsequent calls 【发布时间】:2021-04-25 10:59:26 【问题描述】:

我正在测试 dio 并尝试添加一个拦截器来简单地将令牌添加到未来的请求中,但我得到了一个我似乎无法修复的奇怪结果。作为测试,我只有一个 2 个按钮。单击时应该让我登录并将令牌添加到拦截器,第二个按钮请求身份验证配置文件数据。出于某种原因,单击登录按钮我可以正常登录,但在单击第二个按钮以访问身份验证配置文件数据时得到 403 Forbidden(即使我在添加拦截器后请求配置文件数据)。奇怪的是,当我再次单击第二个按钮(不更改任何代码甚至热重新加载)时,一切正常,并且打印出身份验证配置文件数据。每次我热重启时,我都会回到同样的问题,我对身份验证配置文件数据的第一个请求有 403,但后续请求工作正常。几个小时以来,我一直试图弄清楚发生了什么,但无法理解出了什么问题。请帮忙。谢谢你。 (后端由 django 处理,但问题不存在,因为 api 可以与其他框架一起使用,甚至在 dio 中也可以在随后的按钮按下时正常工作,而不是第一次)

代码


class HomeScreen extends StatefulWidget 
  @override
  _HomeScreenState createState() => _HomeScreenState();


class _HomeScreenState extends State<HomeScreen> 
  Dio session = Dio(
    BaseOptions(
      connectTimeout: 30000,
      baseUrl: 'http://127.0.0.1:8000',
      responseType: ResponseType.json,
      contentType: ContentType.json.toString(),
    ),
  );
  @override
  Widget build(BuildContext context) 
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            RaisedButton(
                child: Text('Log In'),
                onPressed: () async 
                  print('starting');
                  var res = await session.post('/auth/login/',
                      data: 'username': 'tester', 'password': 'tester');
                  print(res.data);
                  session.interceptors.clear();
                  session.interceptors.addAll([
                    InterceptorsWrapper(
                      onRequest: (RequestOptions requestOptions) 
                        session.interceptors.requestLock.lock();
                        String token = res.data['key'];
                        if (token != null) 
                          session.options.headers[HttpHeaders.authorizationHeader] =
                              ‘token $token’;
                        
                        session.interceptors.requestLock.unlock();
                        return requestOptions;
                      ,
                      onError: (e) => print(e.message),
                    ),
                  ]);
                  print(session.interceptors);
                ),
            RaisedButton(
                child: Text('Get Profile'),
                onPressed: () async 
                  session.get('/api/auth/').then((res) => print(res.data));
                ),
          ],
        ),
      ),
    );
  


点击登录按钮时的控制台

Restarted application in 11,586ms.
flutter: starting
flutter: key: 745c0a53112e61d54bea5ea725f7fa92e3a2cdbb
flutter: [Instance of 'InterceptorsWrapper']

第一次点击获取配置文件按钮时的控制台

flutter: Http status error [403]
[VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: DioError [DioErrorType.RESPONSE]: Http status error [403]
#0      DioMixin._request._errorInterceptorWrapper.<anonymous closure>.<anonymous closure>.<anonymous closure>
package:dio/src/dio.dart:870
#1      _rootRunUnary (dart:async/zone.dart:1198:47)
#2      _CustomZone.runUnary (dart:async/zone.dart:1100:19)
#3      _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
#4      Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696:45)
#5      Future._propagateToListeners (dart:async/future_impl.dart:725:32)
#6      Future._completeWithValue (dart:async/future_impl.dart:529:5)
#7      Future._asyncCompleteWithValue.<anonymous closure> (dart:async/future_impl.dart:567:7)
#8      _rootRun (dart:async/zone.dart:1190:13)
#9      _CustomZone.run (dart:async/zone.dart:1093:19)
#10     _CustomZone.runGuarded (dart:async/zone.dart:997:7)
#11     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zon<…>

在随后单击获取配置文件按钮时进行控制台

flutter: id: 3, username: tester, first_name: , last_name: , email: tester@tester.com

【问题讨论】:

不确定这是否有帮助? ***.com/questions/56740793/… @JohnJoe 谢谢,但那是处理刷新过期令牌的问题。我通过登录获得了新的令牌。 【参考方案1】:

5 个小时,终于找出问题所在。

session.options.headers[HttpHeaders.authorizationHeader] = 'token ' + token;

应该是

requestOptions.headers[HttpHeaders.authorizationHeader] = 'token ' + token;

【讨论】:

以上是关于Dio Interceptor 无法处理同一回调中的第一个请求,仅处理后续调用的主要内容,如果未能解决你的问题,请参考以下文章

如何在Inteceptor中处理繁重的计算?

Flutter 如何处理401 未授权的 Dio 拦截器

Kafka Producer拦截器(Interceptor)

Flume 拦截器(interceptor)详解

Dio(Dart 的 Http 客户端)获取请求不适用于拦截器

拦截器(Interceptor)和过滤器(Filter)的区别和执行顺序)