hurshi / dio-http-cache

http cache lib for Flutter dio like RxCache
Apache License 2.0
274 stars 223 forks source link

Error while using #11

Closed BB-fat closed 5 years ago

BB-fat commented 5 years ago

[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: DioError [DioErrorType.DEFAULT]: NoSuchMethodError: The method 'trim' was called on null. Receiver: null Tried calling: trim()

0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)

1 Headers.set (package:dio/src/headers.dart:61:27)

2 Headers.add (package:dio/src/headers.dart:49:29)

3 DioCacheManager._buildResponse. (package:dio_http_cache/src/manager_dio.dart:65:47)

4 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)

5 DioCacheManager._buildResponse (package:dio_http_cache/src/manager_dio.dart:65:21)

6 DioCacheManager._onError (package:dio_http_cache/src/manager_dio.dart:58:16)

#7 InterceptorsWrapper.onError (package:dio/src/interceptor.dart:125:14) #8 DioMixin._request._errorInterceptorWrapper. (package:dio/src/dio.dart:846:40) #9 _rootRunUn<…>
BB-fat commented 5 years ago

反复测试发现是在app启动后一段时间这部分异常,加了个try之后可以正常拿到body,header索性忽略了 Response _buildResponse(String data, RequestOptions options) { var headers = Headers(); // 由于header这里在app启动的时候总抛出异常,所以加一层try忽略 try { options.headers.forEach((k, v) => headers.add(k, v)); }catch(e){} return Response( data: (options.responseType == ResponseType.json) ? jsonDecode(data) : data, headers: headers, extra: options.extra..remove(DIO_CACHE_KEY_MAX_AGE), statusCode: 200); }

hurshi commented 5 years ago

非常感谢你的反馈,但我这边并没有复现呢。 看了你的异常,应该是 header 中有一个 key 为 null, 而导致 crash。 不知你能提供下异常的环境不?方便的话,可以贴一下你请求的数据,比如:

var _dio = Dio(
  BaseOptions(
    baseUrl: "https://www.wanandroid.com/", 
    contentType: "application/x-www-form-urlencoded; charset=utf-8")
  )
  ..interceptors.add(_manager.interceptor)
  ..interceptors.add(LogInterceptor(responseBody: true));

void rq() {
  _dio.post(
      "www.baidu.com", 
      data: {'k': "keyword"}, 
      options: buildCacheOptions(Duration(hours: 1)))
  .then((response) {
      print(">>> ${response.data}");
  });
}

或者提供一个能重现 crash 的 demo 就更好了。

BB-fat commented 5 years ago

的确是这样的,我将dio封装了一下,一开始token默认为null然后返回认证失败的时候再请求token

//  刷新token
  Future _refreshToken() async {
    if (Global.debug) {
      token = "debug";
      return;
    }
    Dio d = Dio();
    d.interceptors.add(LogInterceptor(responseBody: false));
    Response res = await d.post(_baseurl + "/api/v1/auth/token",
        data: json.encode({"id": Global.id, "message": Global.aesKey}));
    if (res.statusCode == 403) {
      Global.id = Global.aesKey = null;
//      TODO 需要登陆时跳转到登陆界面
//      Navigator.popUntil(context, predicate)
    }
    token = res.data["token"];
  }

  Future get(String url,
      {Map<String, dynamic> params = null,
      Duration cacheTime = const Duration(days: 5),
      bool useCache = true}) async {
    Response res = await _dio.get(
      _baseurl + url,
      queryParameters: params,
      options: buildCacheOptions(cacheTime,
          forceRefresh: !useCache, options: Options(headers: {"Token": token})),
    );
    if (res.statusCode == 401) {
      await _refreshToken();
      return get(url, params: params, cacheTime: cacheTime, useCache: useCache);
    } else {
      return res;
    }
  }

所以app的第一次请求header里的token是null。

hurshi commented 5 years ago

Hi, 0.2.1 版本应该就没问题拉。