从JavaScript上载文件到openstack对象存储

时间:2017-08-17 21:10:48

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

我有一个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数据完全以这种方式损坏。

2 个答案:

答案 0 :(得分:2)

<强> 编辑:

  

以下答案现在被认为是性能较差的解决方法As   它会将整个文件编码为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);
});

注意事项。

  • formData请求中的POST应仅包含这些内容 参数。
  • formData中的文件条目应该是最后一个。(不知道为什么 它没有相反的方式)。
  • formData内容,如带有前缀,纪元时间,最大文件的路径 大小,最大文件数和重定向URL应该相同 用于生成签名的那个。否则你会的 获得401 Unauthorized

答案 1 :(得分:1)

  

我尝试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会自动适当地设置内容类型标题。

请注意'Content-Type': multipart/form-data的{​​{3}}会增加33%的额外开销。直接发送base64 encodingBlobs个对象效率更高。

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