request_client.dart 4.98 KB
import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

import '../core/user_util.dart';
import 'api_response/api_response_entity.dart';
import 'api_response/raw_data.dart';
import 'config.dart';
import 'exception.dart';
import 'token_interceptor.dart';

RequestClient requestClient = RequestClient();

class RequestClient {
  late Dio _dio;

  RequestClient() {
    _dio = Dio(BaseOptions(baseUrl: RequestConfig.baseUrl, connectTimeout: RequestConfig.connectTimeout));
    _dio.interceptors.add(TokenInterceptor());
    if (kDebugMode) {
      _dio.interceptors
          .add(PrettyDioLogger(requestHeader: true, requestBody: true, responseHeader: true, maxWidth: 120));
    }
  }

  Future<T?> request<T>(
    String url, {
    required String method,
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    Function(ApiResponse<T>)? onResponse,
    bool Function(ApiException)? onError,
  }) async {
    try {
      Options options = Options()
        ..method = method
        ..headers = headers;

      data = _convertRequestData(data);

      Response response = await _dio.request(url, queryParameters: queryParameters, data: data, options: options);
      print("response.body type=${response.data.runtimeType}");
      return _handleResponse<T>(response, onResponse);
    } catch (e) {
      print("e type=${e.runtimeType}");
      if (e is ApiException && e.code == 405) {
        UserUtil.logout();
        return null;
      }
      var exception = ApiException.from(e);
      if (onError?.call(exception) != true) {
        throw exception;
      }
    }
    return null;
  }

  _convertRequestData(data) {
    if (data != null) {
      data = jsonDecode(jsonEncode(data));
    }
    return data;
  }

  /// get
  Future<T?> get<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    Function(ApiResponse<T>)? onResponse,
    bool Function(ApiException)? onError,
  }) {
    return request(url,
        method: 'GET', queryParameters: queryParameters, headers: headers, onResponse: onResponse, onError: onError);
  }

  /// post
  Future<T?> post<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    Function(ApiResponse<T>)? onResponse,
    bool Function(ApiException)? onError,
  }) {
    return request(url,
        method: "POST",
        queryParameters: queryParameters,
        data: data,
        headers: headers,
        onResponse: onResponse,
        onError: onError);
  }

  /// delete
  Future<T?> delete<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    Function(ApiResponse<T>)? onResponse,
    bool Function(ApiException)? onError,
  }) {
    return request(url,
        method: "DELETE",
        queryParameters: queryParameters,
        data: data,
        headers: headers,
        onResponse: onResponse,
        onError: onError);
  }

  /// put
  Future<T?> put<T>(
    String url, {
    Map<String, dynamic>? queryParameters,
    data,
    Map<String, dynamic>? headers,
    bool showLoading = true,
    Function(ApiResponse<T>)? onResponse,
    bool Function(ApiException)? onError,
  }) {
    return request(url,
        method: "PUT",
        queryParameters: queryParameters,
        data: data,
        headers: headers,
        onResponse: onResponse,
        onError: onError);
  }

  /// 请求响应内容处理
  T? _handleResponse<T>(
    Response response,
    Function(ApiResponse<T>)? onResponse,
  ) {
    int statusCode = response.statusCode ?? -1;
    // 200..299 成功响应
    if (statusCode >= 200 && statusCode <= 299) {
      if (T.toString() == (RawData).toString()) {
        RawData raw = RawData();
        raw.value = response.data;
        return raw as T;
      } else {
        // 应对response的header中content-type: [text/html;charset=utf-8]的情况
        // 实际上都是json格式返回
        Map<String, dynamic> json;
        if (response.data is String) {
          json = jsonDecode(response.data);
        } else {
          json = response.data;
        }
        ApiResponse<T> apiResponse = ApiResponse.fromJson(json);
        onResponse?.call(apiResponse);
        return _handleBusinessResponse<T>(apiResponse);
      }
    } else {
      ApiException exception = ApiException(response.statusCode, ApiException.unknownException);
      print("_handleResponse exception type=${exception.runtimeType}");
      throw exception;
    }
  }

  /// 业务内容处理
  T? _handleBusinessResponse<T>(ApiResponse<T> response) {
    if (response.code == RequestConfig.successCode) {
      return response.data;
    } else {
      ApiException exception = ApiException(response.code, response.msg);
      print("_handleBusinessResponse exception type=${exception.runtimeType}");
      throw exception;
    }
  }
}