本文介绍了使用dio时上传到Azure的文件已损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我的代码:

  FileInfo _fileInfo =等待filePicker();//获取文件路径和文件名//我的getUploadInfo向后端发送呼叫以获取SAS.//我知道这是可行的,因为我的网站使用此SAS可以很好地上传文件UploadInfo uploadInfo =等待getUploadInfo(_fileInfo.fileName,_fileInfo.filePath);最终字节= File(_fileInfo.filePath).readAsBytesSync();尝试 {最终响应=等待myDio.put(uploadInfo.url,数据:字节,onSendProgress:(int发送,int总计){如果(总计!= -1){打印((发送/总计* 100).toStringAsFixed(0)+%");}},选项:dioPrefix.Options(标题:{'x-ms-blob-type':'BlockBlob',内容类型":mime(_fileInfo.filePath),}));}抓住(e){打印(e);} 

这段代码可以上传一个文件.但是我无法打开文件,因为它已损坏.起初,我认为这是一个Content-Type问题,所以我尝试将内容类型标头更改为: application/octet-stream multipart/form-data 也一样那是行不通的.

我也尝试过

  dioPrefix.FormData formData =新的dioPrefix.FormData.fromMap({'文件':等待MultipartFile.fromFile(_fileInfo.filePath,文件名:_fileInfo.fileName,)});...最终响应=等待myDio.put(uploadInfo.url,data:formData,//在dio文档中推荐这种方法onSendProgress:... 

但是这也会损坏文件.它已上传,但无法打开.

已经能够使用此代码成功上传文件,但是通过这种方法,我无法获得任何类型的响应,因此我不知道文件是否成功上传(此外,我可以无法获取上传进度):

  try {最终数据= imageFile.readAsBytesSync();最终响应=等待http.put(//在这里,无论我尝试打印什么,响应都为空网址,正文:数据,标头:{'x-ms-blob-type':'BlockBlob',内容类型":mime(filePath),});... 

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

解决方案

我尝试使用

以blob形式上传的文件的内容是从功能 readAsBytesSync 中的 Uint8List 字节编码的json字符串.

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

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

图2.

因此要解决的问题是编写一个自定义转换器类 PutTransformerForRawData 而不是默认的重写类,以覆盖函数 transformRequest ,如下代码.

  import'dart:typed_data';类PutTransformerForRawData扩展了DefaultTransformer {@overrideFuture< String>transformRequest(RequestOptions options)异步{if(options.data是Uint8List){返回新的String.fromCharCodes(options.data);} else if(options.data是String){返回options.data;}}} 

并通过下面的代码替换默认的变压器.

  var dio = Dio();dio.transformer = PutTransformerForRawData(); 

然后,您可以通过下面的代码获取数据.

  var数据= File(blobName).readAsBytesSync(); 

  var数据= File(blobName).readAsStringSync(); 

注意:自定义传输 PutTransformerForRawData 仅用于上传,请删除下载的&打印代码 Response response = await dio.get(url);print(response.data); ,默认的转换器似乎在检查响应主体是否为json格式,当我上传的文件为示例代码时,出现以下异常.

 未处理的异常:DioError [DioErrorType.DEFAULT]:FormatException:意外字符(在字符1处)导入'dart:typed_data'; 

I'm trying to upload a file from my phone to azure blob storage as a BlockBlob with a SAS. I can get the file to upload, but it can't be opened once downloaded. The file gets corrupted somehow. I thought this was a content-type problem, but I have tried several different approaches to changing to content-type. Nothing has worked so far.

My code:

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

This code uploads a file just fine. But I can't open the file since it becomes corrupted. At first, I thought this was a Content-Type problem, so I've tried changing the content type header to: application/octet-stream and multipart/form-data as well. That doesn't work.

I've also tried to do

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:
...

but this also corrupts the file. It gets uploaded, but I can't open it.

I have been able to successfully upload a file with this code, but with this approach I cannot get any type of response so I have no idea whether it uploaded successfully or not (Also, I can't get the progress of the upload):

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

Any help would be greatly appreciated. Thanks

解决方案

I tried to upload a file using dio in Dart to Azure Blob Storage, and then download and print the content of the file, as the code below.

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

Then, I ran it and got the result as the figure below.

The content of the uploaded file as blob is the json string encoded from a Uint8List bytes from the funtion readAsBytesSync.

I researched the description and the source code of dio, actually I found dio is only suitable for sending the request body of json format, not for raw content as request body.

Fig 1. The default transformer apply for POST method

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

So to fix it is to write a custom transformer class PutTransformerForRawData instead of the default one to override the function transformRequest, as the code below.

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

And to replace the default transformer via the code below.

var dio = Dio();
dio.transformer = PutTransformerForRawData();

Then, you can get the data via the code below.

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

Or

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

Note: the custom transfer PutTransformerForRawData is only for uploading, please remove the download & print code Response response = await dio.get(url); print(response.data);, the default transformer seems to check the response body whether be json format, I got the exception as below when my uploaded file is my sample code.

Unhandled exception:
DioError [DioErrorType.DEFAULT]: FormatException: Unexpected character (at character 1)
import 'dart:typed_data';

这篇关于使用dio时上传到Azure的文件已损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-20 08:48