Flutter 3.24.5
Dart 3.5.4
dio: ^5.3.4
1、新建一个类DioClient
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:energy_manage/base/BaseModel.dart';
import 'package:energy_manage/constantkey/KeyString.dart';
import 'package:energy_manage/pages/login/pages/LoginPage.dart';
import '../base/BaseToast.dart';
import 'package:get/route_manager.dart';
// 请求方式
enum HTTPMethod {
get,
post,
put,
delete,
}
class DioClient {
//创建单例
static DioClient? _instance;
// 确保DioClient 只有一个实例
factory DioClient() => _instance ?? (_instance = DioClient._init());
static Dio _dio = Dio();
DioClient._init() {
BaseOptions options = BaseOptions(
connectTimeout: const Duration(seconds: 10),
receiveTimeout: const Duration(seconds: 10),
);
_dio = Dio(options);
_dio.options.baseUrl = KeyString.baseUrl;
// 拦截器
_dio.interceptors.add(ResponseInterceptor());
// 日志打印
_dio.interceptors.add(LogInterceptor(requestBody: true));
}
DioClient getInstance({String baseUrl = KeyString.baseUrl}) {
_dio.options.baseUrl = baseUrl;
return this;
}
doDio(
path, {
required method,
queryParameters,
data,
options,
cancelToken,
onReceiveProgress,
loading,
}) async {
if (loading == true) {
BaseToast.show("请求中");
}
Response? response;
switch (method) {
case HTTPMethod.get:
response = await _dio.get(path,
queryParameters: queryParameters,
data: data,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress);
break;
case HTTPMethod.post:
response = await _dio.post(path,
queryParameters: queryParameters,
data: data,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress);
case HTTPMethod.put:
response = await _dio.put(path,
queryParameters: queryParameters,
data: data,
options: options,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress);
case HTTPMethod.delete:
response = await _dio.delete(path,
queryParameters: queryParameters,
data: data,
options: options,
cancelToken: cancelToken);
default:
}
if (path == "api/auth/login") {
return response;
}
return BaseModel.fromJson(response?.data);
}
}
//拦截器
class ResponseInterceptor extends InterceptorsWrapper {
// 请求时
@override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
String token = SPUtils().getToken();
if (options.path != "/login") {
//请求头赋值
options.headers["Authorization"] = token;
}
log("queryParameters:${options.queryParameters}");
return handler.next(options);
}
// 返回时
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
BaseToast.cancel();
//成功
print(
"返回数据:地址:${response.requestOptions.uri} \n内容:\n${prettyPrintJson(response.toString())}");
return handler.resolve(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
BaseToast.cancel();
print("请求返回报错:${err.requestOptions.uri} 错误信息:${err.response},${err.error}");
if (err.error.toString().contains("Network is unreachable")) {
BaseToast.showToast("网络连接失败,请检查网络");
return handler
.resolve(Response(requestOptions: err.requestOptions, data: {
"code": -2,
"message": "网络连接失败,请检查网络",
"data": null,
}));
} else if (err.response == null) {
return handler
.resolve(Response(requestOptions: err.requestOptions, data: {
"code": -1,
"message": "请求报错",
"data": null,
}));
} else {
Map map = json.decode(err.response.toString());
if (map["message"] != null) {
BaseToast.showToast("${getErrorMessage(map["message"])}");
}
if (map["status"] == 401) {
await Future.delayed(const Duration(milliseconds: 2000));
if (Get.currentRoute == "/LoginPage" || Get.currentRoute == "/") {
return;
}
Get.offAll(() => Loginpage());
return handler
.resolve(Response(requestOptions: err.requestOptions, data: {
"code": 401,
"message": "登录失效,请重新登录",
"data": null,
}));
}
return handler
.resolve(Response(requestOptions: err.requestOptions, data: {
"code": -1,
"message": "请求报错",
"data": null,
}));
}
}
///错误信息
getErrorMessage(var message) {
String errMessage = "请求报错";
switch (message) {
case "Token has expired":
errMessage = "登录过期,请重新登录";
break;
case "Invalid username":
errMessage = "用户不存在";
break;
}
return errMessage;
}
//格式化打印json数据
String prettyPrintJson(String jsonStr) {
var decodedJson = jsonDecode(jsonStr); // 解析 JSON 字符串
var encoder = JsonEncoder.withIndent(' '); // 使用 2 个空格缩进格式化
return encoder.convert(decodedJson);
}
}
2、新建一个model基类
class BaseModel<T> {
int? code;
T? data;
String? message;
BaseModel({this.code, this.data, this.message});
BaseModel.fromJson(Map<String, dynamic> json) {
code = json["code"];
data = json["data"];
message = json["message"];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = <String, dynamic>{};
map["code"] = code;
map["data"] = data;
map["message"] = message;
return map;
}
}
3、将网络请求都写在同一个类中
import 'package:energy_manage/http/DioClient.dart';
class APIService {
// 登录
static getLogin(Map map) async {
return await DioClient().doDio("api/auth/login",
method: HTTPMethod.post, data: map, loading: true);
}
}
4、使用
Response 是根据封装的返回类型区分 如果返回Response类型,则使用Response类型接收,如果返回的是BaseModel类型,则使用BaseModel类型接收
在DioClient类中判断了login返回的是response 则这个接口使用Response类型接收
其余的使用BaseModel类型接收
if (path == "api/auth/login") {
return response;
}
return BaseModel.fromJson(response?.data);
两种不同类型的返回示例
// 登录返回类型是Response
login() async {
Map<String, dynamic> map = {
"phone": "13100000000",
"password": "a00000000"
};
Response response = await APIService.getLogin(map);
print("返回数据${response.data}");
}
// 登录返回类型是BaseModel
login() async {
Map<String, dynamic> map = {
"phone": "13100000000",
"password": "a00000000"
};
BaseModel response = await APIService.getLogin(map);
print("返回数据${response.code}");
}