使用dio时上传到Azure的文件已损坏

时间:2019-12-11 19:54:56

标签: azure flutter dart azure-blob-storage dio

我正在尝试将手机中的文件作为带有SAS的BlockBlob上传到azure blob存储。我可以上传文件,但下载后无法打开。该文件以某种方式损坏。我以为这是一个内容类型问题,但是我尝试了几种不同的方法来更改为内容类型。到目前为止没有任何工作。

我的代码:

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问题,所以我尝试将内容类型标头更改为:application/octet-streammultipart/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),
  });
...

任何帮助将不胜感激。谢谢

1 个答案:

答案 0 :(得分:0)

我尝试在Dart中使用dio将文件上传到Azure Blob存储,然后下载并打印文件内容,如下代码所示。

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);
}

然后,我运行它并得到如下图的结果。

enter image description here

以blob形式上传的文件的内容是从功能Uint8List的{​​{1}}个字节编码的json字符串。

我研究了readAsBytesSync的描述和源代码,实际上我发现dio仅适合发送json格式的请求正文,不适用于原始内容作为请求正文。

图1.默认转换器适用于POST方法

enter image description here

图2。https://github.com/flutterchina/dio/blob/master/dio/lib/src/transformer.dart

enter image description here

要解决此问题,请编写自定义转换器类dio而不是默认的转换器类,以覆盖函数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;
    }
  }
}

然后,您可以通过下面的代码获得var dio = Dio(); dio.transformer = PutTransformerForRawData();

data

var data = File(blobName).readAsBytesSync();

注意:自定义传输var data = File(blobName).readAsStringSync(); 仅用于上传,请删除下载和打印代码PutTransformerForRawData,默认转换器似乎检查响应正文是否为json格式,我得到了例外当我的上传文件是示例代码时,显示在下面。

Response response = await dio.get(url); print(response.data);
相关问题