This commit is contained in:
chenshuainan
2026-09-28 20:12:34 +08:00
parent 847986f861
commit 5f53bd8f94
60 changed files with 14624 additions and 398 deletions
+38 -1
View File
@@ -1,3 +1,5 @@
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:new_learn/core/logger/app_talker.dart';
@@ -53,6 +55,10 @@ class DioClient {
),
) {
if (enableNetworkLog) {
// 必须在 Talker 之前:把二进制 body 临时换成占位文本,
// 防止 Talker 把整张图(上百万字节)转成巨型日志字符串导致 OOM。
// 真实字节存在 extra 里,由 _buildInterceptors 的 onRequest 还原。
_dio.interceptors.add(_BinaryLogMaskInterceptor());
_dio.interceptors.add(
TalkerDioLogger(
talker: talker,
@@ -88,6 +94,11 @@ class DioClient {
return InterceptorsWrapper(
// ① 请求发出前:加 Token + 打印日志
onRequest: (options, handler) {
// 还原被 _BinaryLogMaskInterceptor 临时替换的二进制 body,保证实际上传内容不变
final realBody = options.extra.remove(_kRealBodyKey);
if (realBody != null) {
options.data = realBody;
}
// OSS 直传会带自己的 authorization 头(OSS4-HMAC-SHA256 签名),
// 任何形式存在 authorization 都不再加 Bearer,否则会覆盖 OSS 签名
final hasAuth =
@@ -177,16 +188,20 @@ class DioClient {
ProgressCallback? onReceiveProgress,
int retries = 0,
Map<String, dynamic>? headers,
Duration? receiveTimeout,
}) async {
var attempt = 0;
while (true) {
try {
final options = (headers != null || receiveTimeout != null)
? Options(headers: headers, receiveTimeout: receiveTimeout)
: null;
final resp = await _dio.get<dynamic>(
path,
queryParameters: query,
cancelToken: cancelToken,
onReceiveProgress: onReceiveProgress,
options: headers == null ? null : Options(headers: headers),
options: options,
);
return resp.data;
} on DioException catch (e) {
@@ -337,3 +352,25 @@ class ApiException implements Exception {
@override
String toString() => message;
}
/// extra 中暂存真实二进制 body 的 key
const String _kRealBodyKey = '_realBinaryBody@dio';
/// 二进制日志屏蔽拦截器(必须在 TalkerDioLogger 之前执行):
/// 把二进制 body 暂存到 extra 并替换成简短占位文本,
/// 避免 Talker 把整张图转成巨型日志字符串、堆积在日志历史里造成 OOM。
/// 真实字节由 _buildInterceptors 的 onRequest 还原,不影响实际请求内容。
class _BinaryLogMaskInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
final data = options.data;
if (data is TypedData) {
options.extra[_kRealBodyKey] = data;
options.data = '<binary ${data.lengthInBytes} bytes>';
} else if (data is Stream<List<int>>) {
options.extra[_kRealBodyKey] = data;
options.data = '<binary stream>';
}
handler.next(options);
}
}