uploadToUrlResponse<T> method
直接上传文件到外部 URL(OSS 直传)
适用于后端返回预签名上传 URL 的场景,直接上传到 OSS(阿里云、腾讯云等) 返回 Response
uploadUrl 完整的上传 URL(包含签名参数)
file 文件对象(File、String 路径或 Uint8List 字节数组)
method HTTP 方法,默认为 'PUT'(OSS 通常使用 PUT)
headers 自定义请求头(OSS 通常需要签名头,如 'Authorization', 'Content-Type' 等)
onProgress 上传进度回调 (已上传字节数, 总字节数)
cancelToken 取消令牌
示例(链式调用):
final result = await http
.send(...)
.extractModel<FileUploadResult>(FileUploadResult.fromConfigJson)
.thenWith((uploadResult) => http.uploadToUrlResponse(
uploadUrl: uploadResult.uploadUrl,
file: file,
method: 'PUT',
headers: uploadResult.contentType != null
? {'Content-Type': uploadResult.contentType!}
: null,
));
示例(单独使用):
final response = await http.uploadToUrlResponse(
uploadUrl: uploadUrl,
file: File('/path/to/image.jpg'),
method: 'PUT',
headers: {'Content-Type': 'image/jpeg'},
onProgress: (sent, total) {
print('上传进度: ${(sent / total * 100).toStringAsFixed(1)}%');
},
);
if (response.isSuccess) {
print('上传成功');
}
Implementation
Future<Response<T>> uploadToUrlResponse<T>({
required String uploadUrl,
required dynamic file,
String method = 'PUT',
Map<String, String>? headers,
void Function(int sent, int total)? onProgress,
dio_package.CancelToken? cancelToken,
}) async {
try {
final dioResponse = await _uploadToUrlInternal(
uploadUrl: uploadUrl,
file: file,
method: method,
headers: headers,
onProgress: onProgress,
cancelToken: cancelToken,
);
// 将 dio_package.Response 转换为 Response<T>
// OSS 直传成功通常返回 200 或 204
final isSuccess = dioResponse.statusCode != null &&
(dioResponse.statusCode == 200 || dioResponse.statusCode == 204);
final response = ApiResponse<T>(
code: dioResponse.statusCode ?? -1,
message: isSuccess ? '上传成功' : '上传失败',
data: dioResponse.data as T?,
isSuccess: isSuccess,
);
// 如果上传失败,自动处理错误(触发错误提示)
if (!isSuccess) {
final config = HttpUtilSafeCall._config;
final errorMessage = response.errorMessage ?? '上传失败,请稍后重试!';
// 调用 handleError(保持接口兼容性,实际错误处理由 HttpConfig.onFailure 统一处理)
response.handleError();
// 延迟调用全局的 onFailure,确保链式调用的 onFailure 可以先执行
// 优先级:链式调用的 onFailure > 全局的 onFailure(如果用户使用了链式调用的 onFailure,就不调用全局的 onFailure)
if (config?.onFailure != null) {
final httpStatusCode = response.httpStatusCode; // 获取 HTTP 状态码
final errorCode = response.errorCode; // 获取业务错误码
Future.microtask(() {
// 再次检查 errorHandled,如果链式调用的 onFailure 已经处理了,就不调用全局的 onFailure
if (!response.errorHandled) {
config!.onFailure!(httpStatusCode, errorCode, errorMessage);
}
});
}
}
return response;
} catch (e) {
// 处理错误
final config = HttpUtilSafeCall._config;
final errorMessage = config?.networkErrorKey ?? '上传失败,请稍后重试!';
if (config?.onFailure != null) {
config!.onFailure!(
null, null, errorMessage); // 上传异常没有 httpStatusCode 和 errorCode
}
return ApiResponse<T>(
code: -1,
message: errorMessage,
data: null,
isSuccess: false,
);
}
}