Flutter PUT 来自文件的 HTTP 请求

Posted

技术标签:

【中文标题】Flutter PUT 来自文件的 HTTP 请求【英文标题】:Flutter PUT HTTP request from file 【发布时间】:2020-02-20 02:31:59 【问题描述】:

需要帮助解决 Flutter 中的 HTTP 请求,使用 PUT 方法通过 API 将 body 上的图像文件发送到 NextCloud 服务器。

与往常一样,我测试了通过 POSTMAN 发送请求以查看发生了什么。在正文选项卡中选择“二进制”并选择图像文件可以正常工作。

文件按预期存在:

我正在使用以下代码在 Flutter 应用上实现这一点:

_imageFile = 包含来自相机或画廊的图像。

RaisedButton(
  color: Colors.blueAccent,
  child: Text('enviar'),
  onPressed: () async 
    String base64Image = base64Encode(_imageFile.readAsBytesSync());
    print(base64Image);
    var client = http.Client();
    var request = http.Request(
        'PUT', Uri.parse('https://host123.com.br/remote.php/dav/files/82427565709/TOOP.jpeg'));
    request.headers.addAll(
        HttpHeaders.authorizationHeader: 'Basic ODI0Mjc1NjU3MDk6Y2xlYW5uZXQ=', 'Content-Type': 'image/jpeg');
    request.body = base64Image;
var streamedResponse = await client.send(request);
    client.close();
    print('ok!');
  ,
),

终端上的结果:

I/flutter ( 8349): /9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAAABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAADTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjY
I/flutter ( 8349): ok

通过APP发送到Nextcloud服务器上的结果:

看起来编码或正文上发送的数据有问题。文件“损坏”

两次测试都是同一个文件。

** 更新 **

按照建议将正文数据更改为字节后,不使用 base64 编码。 (下图)

也尝试使用 .toString() 方法进行转换,文件转到服务器但与以前一样,看起来已损坏。

【问题讨论】:

为什么要在发送之前对正文进行 base 64 编码?只需发送字节。 嗨@RichardHeap,将代码更改如下,但“request.body”需要字符串数据类型。将图片添加到原始帖子中。 将字节分配给request.bodyBytes 【参考方案1】:

不需要自己构造请求,因为http包有一个方便的put方法。此方法(以及更常见的post 方法)采用可选的body 参数,即dynamic。如果您传递字节,这些字节将逐字发送。如果您传递一个字符串,它将被编码为字节并发送。您还可以将字符串映射传递给将进行表单编码的字符串。

我们可以将您的代码简化为:

  var uri = Uri.parse(
      'https://host123.com.br/remote.php/dav/files/82427565709/Lowppp.jpeg');
  var response = await http.put(
    uri,
    headers: 
      HttpHeaders.authorizationHeader: 'Basic xxxxxxx', // insert correct credentials here
      'Content-Type': 'image/jpeg',
    ,
    body: await _imageFile.readAsBytes(),
  );
  print(response.statusCode);

【讨论】:

【参考方案2】:

@RichardHeap 帮助找到了解决方案。 需要将正文作为字节发送,而不是作为 bodyBytes request.bodyBytes = imageBytes;

转换和添加到请求中

完整的代码工作:

List<int> imageBytes = _imageFile.readAsBytesSync();
    var client = http.Client();
    var request = http.Request('PUT', Uri.parse('https://host123.com.br/remote.php/dav/files/82427565709/Lowppp.jpeg'));
    request.headers.addAll(HttpHeaders.authorizationHeader: 'Basic ODI0Mjc1NjU3MDk6Y2xlYW5uZXQ=', 'Content-Type': 'image/jpeg');
    request.bodyBytes = imageBytes;
    var streamedResponse = await client.send(request).then((res) 
      print(res.statusCode);
    ).catchError((err) 
      print(err);
    );
    client.close();

【讨论】:

以上是关于Flutter PUT 来自文件的 HTTP 请求的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 中的 Http PUT 到 .NET Core Web API 提供来自预检请求的 http 401 错误

来自 Flutter Web 的 HTTP Post 请求

QNetworkAccessManager HTTP Put 请求不起作用

使用来自 PHP 客户端的 PUT 请求向 iCal 添加新事件?

http中的put,delete等请求为啥不安全

Express 无法接收来自 axios put 请求的正文