基于Github客户端示例 增加Dio拦截器和日志记录
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import '../index.dart';
class Git {
// 在网络请求过程中可能会需要使用当前的context信息,比如在请求失败时
// 打开一个新路由,而打开新路由需要context信息。
Git([this.context]) {
_options = Options(extra: {"context": context});
}
BuildContext context;
Options _options;
static Dio dio = new Dio(BaseOptions(
connectTimeout: 50000,
receiveTimeout: 50000,
baseUrl: 'https://api.github.com/',
headers: {
HttpHeaders.acceptHeader: "application/vnd.github.squirrel-girl-preview,"
"application/vnd.github.symmetra-preview+json",
},
));
static void init() {
// 添加缓存插件
dio.interceptors.add(Global.netCache);
//添加拦截器
dio.interceptors.add(InterceptorsWrapper(
onRequest: (RequestOptions options) => requestInterceptor(options),
onResponse: (Response response) => responseInterceptor(response),
onError: (DioError dioError) => errorInterceptor(dioError)
));
if (!Global.isRelease) {
// 通过控制台打印所有的请求信息以及相应信息,以方便我们调试请求中的问题
dio.interceptors.add(LoggingInterceptor());
}
// 设置用户token(可能为null,代表未登录)
// dio.options.headers[HttpHeaders.authorizationHeader] = Global.profile.token;
// 在调试模式下需要抓包调试,所以我们使用代理,并禁用HTTPS证书校验
// 启动Charles客户端,配置抓包代理
if (!Global.isRelease) {
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) {
client.findProxy = (uri) {
return "PROXY 192.168.100.37:8888";
};
//代理工具会提供一个抓包的自签名证书,会通不过证书校验,所以我们禁用证书校验
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
};
}
}
static dynamic requestInterceptor(RequestOptions options) async {
// 请求拦截器
var token = Global.profile.token;
options.headers[HttpHeaders.authorizationHeader] = Global.profile.token;
options.headers.addAll({"X-Token": "$token"});
return options;
}
static dynamic responseInterceptor(Response options) async {
// 响应拦截器
// if (options.headers.value("verifyToken") != null) {
// //if the header is present, then compare it with the Shared Prefs key
// var verifyToken = Global.profile.token;
// // if the value is the same as the header, continue with the request
// if (options.headers.value("verifyToken") != verifyToken) {
// return DioError(request: options.request, error: "User is no longer active");
// }
// }
// if (options.data['code'] == 20000){
// return options.data['data'];
// }
return options;
}
static dynamic errorInterceptor(DioError dioError) {
// 错误拦截器
if (dioError.message.contains("ERROR_001")) {
// this will push a new route and remove all the routes that were present
final GlobalKey<NavigatorState> navigatorKey = new GlobalKey<NavigatorState>();
navigatorKey.currentState.pushNamedAndRemoveUntil(
"/login", (Route<dynamic> route) => false);
}
return dioError;
}
// 登录接口,登录成功后返回用户信息
Future<User> login(String login, String pwd) async {
String basic = 'Basic ' + base64.encode(utf8.encode('$login:$pwd'));
var r = await dio.get(
"/users/$login",
options: _options.merge(headers: {
HttpHeaders.authorizationHeader: basic
}, extra: {
"noCache": true, //本接口禁用缓存
}),
);
//登录成功后更新公共头(authorization),此后的所有请求都会带上用户身份信息
dio.options.headers[HttpHeaders.authorizationHeader] = basic;
//清空所有缓存
Global.netCache.cache.clear();
//更新profile中的token信息
Global.profile.token = basic;
return User.fromJson(r.data);
}
//获取用户项目列表
Future<List<Repo>> getRepos(
{Map<String, dynamic> queryParameters, //query参数,用于接收分页信息
refresh = false}) async {
if (refresh) {
// 列表下拉刷新,需要删除缓存(拦截器中会读取这些信息)
_options.extra.addAll({"refresh": true, "list": true});
}
var r = await dio.get<List>(
"user/repos",
queryParameters: queryParameters,
options: _options,
);
return r.data.map((e) => Repo.fromJson(e)).toList();
}
}
class LoggingInterceptor extends Interceptor{
// 通过控制台打印所有的请求信息以及相应信息,以方便我们调试请求中的问题
int _maxCharactersPerLine = 200;
@override
Future onRequest(RequestOptions options) {
debugPrint("--> ${options.method} ${options.path}");
debugPrint("Content type: ${options.contentType}");
debugPrint("<-- END HTTP");
return super.onRequest(options);
}
@override
Future onResponse(Response response) {
debugPrint(
"<-- ${response.statusCode} ${response.request.method} ${response.request.path}");
String responseAsString = response.data.toString();
if (responseAsString.length > _maxCharactersPerLine) {
int iterations =
(responseAsString.length / _maxCharactersPerLine).floor();
for (int i = 0; i <= iterations; i++) {
int endingIndex = i * _maxCharactersPerLine + _maxCharactersPerLine;
if (endingIndex > responseAsString.length) {
endingIndex = responseAsString.length;
}
debugPrint(responseAsString.substring(
i * _maxCharactersPerLine, endingIndex));
}
} else {
debugPrint(response.data);
}
debugPrint("<-- END HTTP");
return super.onResponse(response);
}
@override
Future onError(DioError err) {
debugPrint("<-- Error -->");
debugPrint(err.error);
debugPrint(err.message);
return super.onError(err);
}
}