Dio网络请求框架之LogInterceptor、CacheInterceptor源码分析(九)

375 阅读3分钟

LogInterceptor

/// [LogInterceptor] is used to print logs during network requests.
/// It's better to add [LogInterceptor] to the tail of the interceptor queue,
/// otherwise the changes made in the interceptor behind A will not be printed out.
/// This is because the execution of interceptors is in the order of addition.
class LogInterceptor extends Interceptor {
  LogInterceptor({
    this.request = true,
    this.requestHeader = true,
    this.requestBody = false,
    this.responseHeader = true,
    this.responseBody = false,
    this.error = true,
    this.logPrint = print,
  });

  /// Print request [Options]
  bool request;

  /// Print request header [Options.headers]
  bool requestHeader;

  /// Print request data [Options.data]
  bool requestBody;

  /// Print [Response.data]
  bool responseBody;

  /// Print [Response.headers]
  bool responseHeader;

  /// Print error message
  bool error;

  /// Log printer; defaults print log to console.
  /// In flutter, you'd better use debugPrint.
  /// you can also write log in a file, for example:
  ///```dart
  ///  final file=File("./log.txt");
  ///  final sink=file.openWrite();
  ///  dio.interceptors.add(LogInterceptor(logPrint: sink.writeln));
  ///  ...
  ///  await sink.close();
  ///```
  void Function(Object object) logPrint;

  @override
  void onRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    logPrint('*** Request ***');
    _printKV('uri', options.uri);
    //options.headers;

    if (request) {
      _printKV('method', options.method);
      _printKV('responseType', options.responseType.toString());
      _printKV('followRedirects', options.followRedirects);
      _printKV('persistentConnection', options.persistentConnection);
      _printKV('connectTimeout', options.connectTimeout);
      _printKV('sendTimeout', options.sendTimeout);
      _printKV('receiveTimeout', options.receiveTimeout);
      _printKV(
        'receiveDataWhenStatusError',
        options.receiveDataWhenStatusError,
      );
      _printKV('extra', options.extra);
    }
    if (requestHeader) {
      logPrint('headers:');
      options.headers.forEach((key, v) => _printKV(' $key', v));
    }
    if (requestBody) {
      logPrint('data:');
      _printAll(options.data);
    }
    logPrint('');

    handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) async {
    logPrint('*** Response ***');
    _printResponse(response);
    handler.next(response);
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) async {
    if (error) {
      logPrint('*** DioError ***:');
      logPrint('uri: ${err.requestOptions.uri}');
      logPrint('$err');
      if (err.response != null) {
        _printResponse(err.response!);
      }
      logPrint('');
    }

    handler.next(err);
  }

  void _printResponse(Response response) {
    _printKV('uri', response.requestOptions.uri);
    if (responseHeader) {
      _printKV('statusCode', response.statusCode);
      if (response.isRedirect == true) {
        _printKV('redirect', response.realUri);
      }

      logPrint('headers:');
      response.headers.forEach((key, v) => _printKV(' $key', v.join('\r\n\t')));
    }
    if (responseBody) {
      logPrint('Response Text:');
      _printAll(response.toString());
    }
    logPrint('');
  }

  void _printKV(String key, Object? v) {
    logPrint('$key: $v');
  }

  void _printAll(msg) {
    msg.toString().split('\n').forEach(logPrint);
  }
}

LogInterceptor 是用于在网络请求期间打印日志的拦截器。

它可以打印请求和响应的详细信息,包括请求URL、请求头、请求数据、响应状态码、响应头以及响应数据等。你可以根据需要设置哪些信息需要打印。

以下是 LogInterceptor 提供的参数和功能:

  • request: 是否打印请求的基本信息。
  • requestHeader: 是否打印请求的头部信息。
  • requestBody: 是否打印请求的数据信息。
  • responseHeader: 是否打印响应的头部信息。
  • responseBody: 是否打印响应的数据信息。
  • error: 是否打印错误信息。
  • logPrint: 用于打印日志的回调函数,默认是打印到控制台。

在具体的请求、响应和错误处理方法中,LogInterceptor 根据设置的参数,打印相关信息。

例如,在请求方法中,会打印请求的基本信息、头部信息和数据信息。在响应方法中,会打印响应的基本信息、头部信息和数据信息。在错误方法中,会打印错误信息。

使用 LogInterceptor 可以帮助你在开发过程中更方便地跟踪和调试网络请求,了解请求和响应的具体细节。但需要注意,在生产环境中,建议关闭或移除日志拦截器,以避免不必要的信息暴露。

CacheInterceptor

class CacheInterceptor extends Interceptor {
  CacheInterceptor();

  final _cache = <Uri, Response>{};

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final response = _cache[options.uri];
    if (options.extra['refresh'] == true) {
      print('${options.uri}: force refresh, ignore cache! \n');
      return handler.next(options);
    } else if (response != null) {
      print('cache hit: ${options.uri} \n');
      return handler.resolve(response);
    }
    super.onRequest(options, handler);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    _cache[response.requestOptions.uri] = response;
    super.onResponse(response, handler);
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    print('onError: $err');
    super.onError(err, handler);
  }
}

CacheInterceptor 是一个自定义的拦截器,用于实现简单的请求缓存功能。它可以在请求发送前检查缓存是否存在,并在响应返回后将响应数据缓存起来,以便在后续相同请求时直接返回缓存数据,避免重复请求。

该拦截器具有以下功能:

  • _cache: 一个存储缓存数据的字典,使用请求的 URI 作为键,响应数据作为值。

在请求方法中,它会检查缓存中是否存在对应的响应数据。如果存在,则直接返回缓存的响应数据,而不再进行实际的网络请求。如果请求中设置了 refresh 参数为 true,则会强制刷新数据,忽略缓存,并继续进行实际的网络请求。

在响应方法中,它会将收到的响应数据缓存起来,以便后续的相同请求可以直接返回缓存数据。

在错误方法中,它会简单地打印错误信息。

注意:这只是一个简单的示例实现,实际的缓存机制可能更复杂,例如可以设置缓存的有效期、清除过期的缓存等。缓存策略通常需要根据具体的应用场景进行定制。