init method
void
init({})
初始化 Dio,baseUrl 例如 http://127.0.0.1:9501
acceptLanguage 默认 zh-CN,有值则以客户端传入为准。
Implementation
void init({
required String baseUrl,
required String aesKey,
Duration? connectTimeout,
String? acceptLanguage,
}) {
if (aesKey.isEmpty) {
throw GoChatException('aesKey 不能为空(须与后端 app.aes_key 一致)');
}
_baseUrl = baseUrl.endsWith('/')
? baseUrl.substring(0, baseUrl.length - 1)
: baseUrl;
_aesKey = aesKey;
_acceptLanguage = (acceptLanguage == null || acceptLanguage.isEmpty)
? defaultAcceptLanguage
: acceptLanguage;
_dio = Dio(
BaseOptions(
baseUrl: _baseUrl,
connectTimeout: connectTimeout ?? const Duration(seconds: 15),
receiveTimeout: const Duration(seconds: 30),
sendTimeout: const Duration(seconds: 30),
contentType: Headers.jsonContentType,
responseType: ResponseType.json,
headers: {
'Accept': 'application/json',
'Accept-Language': _acceptLanguage,
},
),
);
_dio!.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) async {
options.headers['Accept-Language'] = _acceptLanguage;
if (_token != null && _token!.isNotEmpty) {
options.headers['Authorization'] = 'Bearer $_token';
}
final data = options.data;
// FormData 明文 multipart:不加密、不带 AES 头,交由 Dio 设置 boundary
if (data is FormData) {
options.headers.remove(Headers.contentTypeHeader);
options.headers.remove(kAesContentEncodingHeader);
} else {
options.headers[kAesContentEncodingHeader] =
kAesContentEncodingValue;
if (data != null) {
final plain = data is String
? data
: jsonEncode(data is Map ? data : {'data': data});
try {
options.data = await AesEnvelope.encrypt(plain, _aesKey);
} catch (e, st) {
handler.reject(
DioException(
requestOptions: options,
error: e,
stackTrace: st,
),
);
return;
}
}
}
GoChatLogger.d('HTTP → ${options.method} ${options.uri}');
handler.next(options);
},
onResponse: (response, handler) async {
// 滑动刷新 Token
final newToken = response.headers.value('Refresh-Access-Token');
if (newToken != null && newToken.isNotEmpty) {
setToken(newToken);
onTokenRefreshed?.call(newToken);
}
try {
response.data = await _maybeDecrypt(response);
handler.next(response);
} catch (e, st) {
handler.reject(
DioException(
requestOptions: response.requestOptions,
response: response,
error: e,
stackTrace: st,
),
);
}
},
onError: (error, handler) async {
final status = error.response?.statusCode;
if (status == 401) {
onUnauthorized?.call();
}
if (error.response?.data != null) {
try {
error.response!.data = await _maybeDecrypt(error.response!);
} catch (_) {}
}
handler.next(error);
},
),
);
}