正在将文件从 JavaScript 上传到 openstack 对象存储

Uploading file to openstack object storage from JavaScript

我有一个 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 之类的文件这样数据就完全损坏了。

编辑:

The following answer is now considered a less performing workaround As it will encode the entire file to base64 multipart form data. I would suggest go ahead with @georgeawg's Answer if you are not Looking for a formData + POST solution

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

这是它的简介。

首先,您需要使用以下 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 中调用 post 容器。

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中的文件条目应该是最后一个。(不知道为什么 反过来就不行了)。
  • 表单数据内容,如带前缀的路径、纪元时间、最大文件 大小、最大文件数和重定向 url 应与 用于生成签名的那个。否则你会 得到一个 401 Unauthorized.

I tried the FileReader to read the selected file as a binary string and wrote the content to the request body instead of FormData and the request which works fine for text files but not the binary files like XLSX or PDF The data is entirely corrupted this way.

$http service is to use Content-Type: application/json and to transform objects to JSON strings. For files from a 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 将自动适当地设置内容类型 header。

注意 base64 encoding of 'Content-Type': multipart/form-data adds 33% extra overhead. It is more efficient to send Blobs and File objects 直接。

将二进制数据作为二进制字符串发送,会损坏数据,因为 XHR API converts strings from DOMSTRING (UTF-16) to UTF-8. Avoid binary strings 因为它们是 non-standard 并且已过时。