使用 dio 时上传到 Azure 的文件已损坏
uploaded files to Azure are corrupted when using dio
我正在尝试将文件从我的 phone 上传到 Azure Blob 存储,作为带有 SAS 的 BlockBlob。我可以获取要上传的文件,但下载后无法打开。该文件以某种方式损坏。我认为这是一个 content-type 问题,但我尝试了几种不同的方法来更改为 content-type。到目前为止没有任何效果。
我的代码:
FileInfo _fileInfo = await filePicker(); // get the file path and file name
// my getUploadInfo fires a call to my backend to get a SAS.
// I know for a fact that this works because my website uses this SAS to upload files perfectly fine
UploadInfo uploadInfo = await getUploadInfo(_fileInfo.fileName, _fileInfo.filePath);
final bytes = File(_fileInfo.filePath).readAsBytesSync();
try {
final response = await myDio.put(
uploadInfo.url,
data: bytes,
onSendProgress:
(int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
options:
dioPrefix.Options(headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': mime(_fileInfo.filePath),
})
);
} catch (e) {
print(e);
}
此代码可以很好地上传文件。但是我无法打开文件,因为它已损坏。起初,我认为这是一个 Content-Type 问题,所以我尝试将内容类型 header 更改为:application/octet-stream
和 multipart/form-data
。那不行。
我也试过
dioPrefix.FormData formData =
new dioPrefix.FormData.fromMap({
'file': await MultipartFile.fromFile(
_fileInfo.filePath,
filename: _fileInfo.fileName,
)
});
...
final response = await myDio.put(
uploadInfo.url,
data: formData, // This approach is recommended on the dio documentation
onSendProgress:
...
但这也会损坏文件。上传了,打不开
我已经能够使用此代码成功上传文件,但是使用这种方法我无法获得任何类型的响应,所以我不知道它是否上传成功(还有,我无法获取上传进度):
try {
final data = imageFile.readAsBytesSync();
final response = await http.put( // here, response is empty no matter what i try to print
url,
body: data,
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': mime(filePath),
});
...
如有任何帮助,我们将不胜感激。谢谢
我尝试在Dart中使用dio
上传一个文件到Azure Blob Storage,然后下载并打印文件内容,如下代码。
import 'package:dio/dio.dart';
import 'dart:io';
main() async {
var accountName = '<account name>';
var containerName = '<container name>';
var blobName = '<blob name>';
var sasTokenContainerLevel = '<container level sas token copied from Azure Storage Explorer, such as `st=2019-12-31T07%3A17%3A31Z&se=2020-01-01T07%3A17%3A31Z&sp=racwdl&sv=2018-03-28&sr=c&sig=xxxxxxxxxxxxxxxxxxxxxxxxxx`';
var url = 'https://$accountName.blob.core.windows.net/$containerName/$blobName?$sasTokenContainerLevel';
var data = File(blobName).readAsBytesSync();
var dio = Dio();
try {
final response = await dio.put(
url,
data: data,
onSendProgress:
(int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
options: Options(
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': 'text/plain',
})
);
print(response.data);
} catch (e) {
print(e);
}
Response response = await dio.get(url);
print(response.data);
}
然后,我运行它,结果如下图。
作为 blob 的上传文件的内容是从函数 readAsBytesSync
.
的 Uint8List
字节编码的 json 字符串
我研究了dio
的描述和源代码,实际上我发现dio
只适合发送json格式的请求体,不适合作为请求的原始内容正文
图1.默认t运行sformer申请POST方法
图 2.https://github.com/flutterchina/dio/blob/master/dio/lib/src/transformer.dart
所以要修复它就是写一个自定义的t运行sformer class PutTransformerForRawData
而不是默认的来覆盖函数transformRequest
,如下代码.
import 'dart:typed_data';
class PutTransformerForRawData extends DefaultTransformer {
@override
Future<String> transformRequest(RequestOptions options) async {
if(options.data is Uint8List) {
return new String.fromCharCodes(options.data);
} else if(options.data is String) {
return options.data;
}
}
}
并通过以下代码替换默认的 t运行sformer。
var dio = Dio();
dio.transformer = PutTransformerForRawData();
然后,您可以通过下面的代码获取data
。
var data = File(blobName).readAsBytesSync();
或
var data = File(blobName).readAsStringSync();
注意:自定义的t运行sfer PutTransformerForRawData
只用于上传,请去掉下载&打印代码Response response = await dio.get(url); print(response.data);
,默认的t运行sformer好像是检查响应正文是否为json格式,我上传的文件是我的示例代码时出现如下异常。
Unhandled exception:
DioError [DioErrorType.DEFAULT]: FormatException: Unexpected character (at character 1)
import 'dart:typed_data';
我正在尝试将文件从我的 phone 上传到 Azure Blob 存储,作为带有 SAS 的 BlockBlob。我可以获取要上传的文件,但下载后无法打开。该文件以某种方式损坏。我认为这是一个 content-type 问题,但我尝试了几种不同的方法来更改为 content-type。到目前为止没有任何效果。
我的代码:
FileInfo _fileInfo = await filePicker(); // get the file path and file name
// my getUploadInfo fires a call to my backend to get a SAS.
// I know for a fact that this works because my website uses this SAS to upload files perfectly fine
UploadInfo uploadInfo = await getUploadInfo(_fileInfo.fileName, _fileInfo.filePath);
final bytes = File(_fileInfo.filePath).readAsBytesSync();
try {
final response = await myDio.put(
uploadInfo.url,
data: bytes,
onSendProgress:
(int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
options:
dioPrefix.Options(headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': mime(_fileInfo.filePath),
})
);
} catch (e) {
print(e);
}
此代码可以很好地上传文件。但是我无法打开文件,因为它已损坏。起初,我认为这是一个 Content-Type 问题,所以我尝试将内容类型 header 更改为:application/octet-stream
和 multipart/form-data
。那不行。
我也试过
dioPrefix.FormData formData =
new dioPrefix.FormData.fromMap({
'file': await MultipartFile.fromFile(
_fileInfo.filePath,
filename: _fileInfo.fileName,
)
});
...
final response = await myDio.put(
uploadInfo.url,
data: formData, // This approach is recommended on the dio documentation
onSendProgress:
...
但这也会损坏文件。上传了,打不开
我已经能够使用此代码成功上传文件,但是使用这种方法我无法获得任何类型的响应,所以我不知道它是否上传成功(还有,我无法获取上传进度):
try {
final data = imageFile.readAsBytesSync();
final response = await http.put( // here, response is empty no matter what i try to print
url,
body: data,
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': mime(filePath),
});
...
如有任何帮助,我们将不胜感激。谢谢
我尝试在Dart中使用dio
上传一个文件到Azure Blob Storage,然后下载并打印文件内容,如下代码。
import 'package:dio/dio.dart';
import 'dart:io';
main() async {
var accountName = '<account name>';
var containerName = '<container name>';
var blobName = '<blob name>';
var sasTokenContainerLevel = '<container level sas token copied from Azure Storage Explorer, such as `st=2019-12-31T07%3A17%3A31Z&se=2020-01-01T07%3A17%3A31Z&sp=racwdl&sv=2018-03-28&sr=c&sig=xxxxxxxxxxxxxxxxxxxxxxxxxx`';
var url = 'https://$accountName.blob.core.windows.net/$containerName/$blobName?$sasTokenContainerLevel';
var data = File(blobName).readAsBytesSync();
var dio = Dio();
try {
final response = await dio.put(
url,
data: data,
onSendProgress:
(int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
options: Options(
headers: {
'x-ms-blob-type': 'BlockBlob',
'Content-Type': 'text/plain',
})
);
print(response.data);
} catch (e) {
print(e);
}
Response response = await dio.get(url);
print(response.data);
}
然后,我运行它,结果如下图。
作为 blob 的上传文件的内容是从函数 readAsBytesSync
.
Uint8List
字节编码的 json 字符串
我研究了dio
的描述和源代码,实际上我发现dio
只适合发送json格式的请求体,不适合作为请求的原始内容正文
图1.默认t运行sformer申请POST方法
图 2.https://github.com/flutterchina/dio/blob/master/dio/lib/src/transformer.dart
所以要修复它就是写一个自定义的t运行sformer class PutTransformerForRawData
而不是默认的来覆盖函数transformRequest
,如下代码.
import 'dart:typed_data';
class PutTransformerForRawData extends DefaultTransformer {
@override
Future<String> transformRequest(RequestOptions options) async {
if(options.data is Uint8List) {
return new String.fromCharCodes(options.data);
} else if(options.data is String) {
return options.data;
}
}
}
并通过以下代码替换默认的 t运行sformer。
var dio = Dio();
dio.transformer = PutTransformerForRawData();
然后,您可以通过下面的代码获取data
。
var data = File(blobName).readAsBytesSync();
或
var data = File(blobName).readAsStringSync();
注意:自定义的t运行sfer PutTransformerForRawData
只用于上传,请去掉下载&打印代码Response response = await dio.get(url); print(response.data);
,默认的t运行sformer好像是检查响应正文是否为json格式,我上传的文件是我的示例代码时出现如下异常。
Unhandled exception:
DioError [DioErrorType.DEFAULT]: FormatException: Unexpected character (at character 1)
import 'dart:typed_data';