【问题标题】:Uploading file to openstack object storage from JavaScript从 JavaScript 上传文件到 openstack 对象存储
【发布时间】:2017-08-17 21:10:47
【问题描述】:

我有一个 openstack 对象存储容器,我正在尝试直接从浏览器上传文件。

根据文档here,我可以使用PUT 请求上传文件,我正在使用Angularjs 提供的$http.put 方法执行此操作,如下所示。

$http.put(temporaryUploadUrl,
    formData,
    {
        headers: {
            'Content-Type': undefined
        }
    }
).then(function (res) {
    console.log("Success");
});

文件上传成功,验证没有问题,并给我一个201 Created 响应。然而,该文件现在在其顶部和底部包含垃圾行,因为它是使用 FormData() 发送的多部分请求。

上传前的示例文件内容:

Some sample text 
here is more text 
here is some other text

从openstack容器下载回来后的文件内容:

------WebKitFormBoundaryTEeQZVW5hNSWtIqS
Content-Disposition: form-data; name="file"; filename="c.txt"
Content-Type: text/plain
Some sample text 
here is more text 
here is some other text
------WebKitFormBoundaryTEeQZVW5hNSWtIqS--

我尝试使用FileReader 将所选文件作为二进制字符串读取,并将内容写入请求正文而不是FormData,并且该请求适用于文本文件但不适用于XLSXPDF 数据被这样完全破坏了。

【问题讨论】:

  • @georgeawg 请再次访问该问题。我已经编辑了错误
  • 只有当有 cmets 告诉我为什么所有这些反对票...:|
  • 发送Content-Type: multipart/form-data时的“垃圾线”是boundaries。您尝试了所有除了直接发送File对象的方法。

标签: angularjs openstack form-data angularjs-http openstack-swift


【解决方案1】:

编辑:

以下答案现在被认为是性能较差的解决方法 它将整个文件编码为 base64 多部分表单数据。我会 如果您不想要,建议继续使用@georgeawg 的答案 formData + POST 解决方案

Openstack 还提供了一种不同的方法,使用 FormData 一次性上传一个或多个文件,如 documentation 中所述。有趣的是,这在谷歌搜索中从未可见。

这里是它的简介。

首先,您需要使用以下 python 过程生成类似于 tempUrl 签名的签名。

import hmac
from hashlib import sha1
from time import time
path = '/v1/my_account/container/object_prefix'
redirect = 'https://myserver.com/some-page'
max_file_size = 104857600
max_file_count = 1
expires = 1503124957
key = 'mySecretKey'
hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, redirect,
max_file_size, max_file_count, expires)
signature = hmac.new(key, hmac_body, sha1).hexdigest()

然后在你的javascript调用中像这样发布到容器。

var formData = new FormData();
formData.append("max_file_size", '104857600');
formData.append("max_file_count", '1');
formData.append("expires", '1503124957');
formData.append("signature", signature);
formData.append("redirect", redirect);
formData.append("file",fileObject);
$http.post(
    "https://www.example.com/v1/my_account/container/object_prefix",
    formData,
    {
        headers: {'Content-Type': undefined},
        transformRequest: angular.identity
    }
).then(function (res) {
    console.log(response);
});

注意事项。

  • POST 请求中的formData 应该只包含这些 参数。
  • formData 中的文件条目应该是最后一个。(不知道为什么 反过来就不行了)。
  • formData 内容,如带前缀的路径、纪元时间、最大文件 大小、最大文件数和重定向 url 应该与 用于生成签名的那个。否则你会 获取401 Unauthorized

【讨论】:

    【解决方案2】:

    我尝试使用FileReader 将所选文件作为二进制字符串读取,并将内容写入请求正文而不是FormData,并且该请求适用于文本文件,但不适用于 XLSX 或 PDF 等二进制文件数据以这种方式完全损坏。

    $http service 的默认操作是使用Content-Type: application/json 并将对象转换为JSON strings。对于来自FileList 的文件,需要覆盖默认值:

    var config = { headers: {'Content-Type': undefined} };
    
    $http.put(url, fileList[0], config)
      .then(function(response) {
         console.log("Success");
    }).catch(function(response) {
         console.log("Error: ", response.status);
         throw response;
    });
    

    通过设置Content-Type: undefinedXHR send method 将自动适当地设置内容类型标头。

    请注意,base64 encoding'Content-Type': multipart/form-data 会增加 33% 的额外开销。直接发送BlobsFile对象效率更高。

    将二进制数据作为二进制字符串发送会损坏数据,因为XHR API 会将字符串从DOMSTRING (UTF-16) 转换为UTF-8。避免使用 binary strings,因为它们是非标准且已过时的。

    【讨论】:

    • 当我尝试上传到 Openstack 临时 URL 时,这不起作用。但是,文件条目已创建,文件下载为 0 字节。(空文件)
    • 通过在您的代码中删除 transformRequest: angular.identity 来修复它。请更新您的答案,以便我接受。
    • Blob 检测被添加到 AngularJS v1.3.0 中,commit 7c858ce。 FormData 检测已添加到 v1.3.7,commit d80ce4a
    • 我使用的是 1.3.17
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    • 2021-01-16
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    • 2014-08-24
    相关资源
    最近更新 更多