javascript - Cordova 插件文件传输 : How do you upload a file to S3 using a signed URL?

标签 javascript android cordova amazon-s3 ionic-framework

我可以使用文件选择器和常规 XMLHttpRequest(我用它来测试 S3 设置)上传到 S3,但无法弄清楚如何使用 cordova 文件传输成功完成插件。

我认为这要么是因为插件没有构建正确的可签名请求,要么是不喜欢给定的本地文件 uri。我试过使用从 header 到 uri 类型的每个参数,但文档没有太大帮助,插件源是博洛尼亚。

请求需要签名匹配的字符串如下:

PUT


1391784394
x-amz-acl:public-read
/the-app/317fdf654f9e3299f238d97d39f10fb1

任何想法,或可能的工作代码示例?

最佳答案

有点晚了,但我只是花了几天时间来解决这个问题,以防万一其他人遇到问题,这就是如何使用 AWS SDK 的 javascript 版本上传图像以创建预签名 URL。

解决问题的关键在StringToSign XML 元素 SignatureDoesNotMatch从亚马逊返回的错误。就我而言,它看起来像这样:

<StringToSign>
    PUT\n\nmultipart/form-data; boundary=+++++org.apache.cordova.formBoundary\n1481366396\n/bucketName/fileName.jpg
</StringToSign>

当您使用 aws-sdk生成用于上传到 S3 的预签名 URL,它会在内部根据您要发出的请求的各种元素构建一个字符串,然后使用您的 AWS secret 创建它的 SHA1 哈希。此哈希是作为参数附加到 URL 的签名,当您获得 SignatureDoesNotMatch 时不匹配的内容。错误。

因此您已经创建了预签名 URL,并将其传递给 cordova-plugin-file-transfer使您的 HTTP 请求上传文件。当该请求到达亚马逊的服务器时,服务器将自己根据请求 header 等构建一个字符串,对其进行哈希处理并将该哈希值与 URL 上的签名进行比较。如果哈希值不匹配,则返回可怕的...

The request signature we calculated does not match the signature you provided. Check your key and signing method.

StringToSign 的内容我上面提到的元素是服务器构建和散列以与预签名 URL 上的签名进行比较的字符串。因此,为避免出现错误,您需要确保 aws-sdk 构建的字符串与服务器构建的相同。

经过一番挖掘,我最终在 aws-sdk 中找到了负责创建要散列的字符串的代码。 .它位于(从版本 2.7.12 开始):

node_modules/aws-sdk/lib/signers/s3.js

在第 168 行的底部有一个 sign方法:

sign: function sign(secret, string) { return AWS.util.crypto.hmac(secret, string, 'base64', 'sha1'); }

如果你把 console.log在那里,string是你所追求的。一旦你制作了 string传递给此方法的内容与 StringToSign 的内容相同在从 Amazon 返回的错误消息中,天将打开,您的文件将毫不费力地流入您的存储桶。

在我运行 node.js 的服务器上,我最初创建我的预签名 URL 是这样的:

var AWS = require('aws-sdk');

var s3 = new AWS.S3(options = {
    endpoint: 'https://s3-eu-west-1.amazonaws.com',
    accessKeyId: "ACCESS_KEY",
    secretAccessKey: "SECRET_KEY"
});

var params = {
    Bucket: 'bucketName',
    Key: imageName,
    Expires: 60
};

var signedUrl = s3.getSignedUrl('putObject', params);

//return signedUrl

这产生了一个像这样的签名字符串,类似于 OP 的:

PUT


1481366396
/bucketName/fileName.jpg

在客户端,我将此预签名 URL 与 cordova-plugin-file-transfer 一起使用像这样(我使用的是 Ionic 2,所以插件被包装在他们的原生包装器中):

let success = (result: any) : void => { 
    console.log("upload success");
}

let failed = (err: any) : void => {
    let code = err.code;
    alert("upload error - " + code);
}

let ft = new Transfer();

var options = {
    fileName: filename,
    mimeType: 'image/jpeg',
    chunkedMode: false,
    httpMethod:'PUT',
    encodeURI: false,
};

ft.upload(localDataURI, presignedUrlFromServer, options, false)
.then((result: any) => {
    success(result);
}).catch((error: any) => {
    failed(error);
});

运行代码产生了签名不匹配错误,<StringToSign> 中的字符串元素看起来像这样:

PUT

multipart/form-data; boundary=+++++org.apache.cordova.formBoundary
1481366396
/bucketName/fileName.jpg

所以我们可以看到cordova-plugin-file-transfer已添加自己的 Content-Type导致签名字符串不一致的 header 。在docs关于传递到上传方法的选项对象,它说:

headers: A map of header name/header values. Use an array to specify more than one value. On iOS, FireOS, and Android, if a header named Content-Type is present, multipart form data will NOT be used. (Object)

所以基本上,如果没有 Content-Type header 已设置,它将默认为多部分表单数据。

好的,现在我们知道了问题的原因,这是一个非常简单的修复。在服务器端我添加了一个 ContentTypeparams传递给 S3 的对象 getSignedUrl方法:

var params = {
    Bucket: 'bucketName',
    Key: imageName,
    Expires: 60,
    ContentType: 'image/jpeg' // <---- content type added here
};

并在客户端添加了一个headers反对 options传递给 cordova-plugin-file-transfer的上传方法:

var options = {
    fileName: filename,
    mimeType: 'image/jpeg',
    chunkedMode: false,
    httpMethod:'PUT',
    encodeURI: false,
    headers: { // <----- headers object added here
        'Content-Type': 'image/jpeg',
    }
};

嘿嘿!上传现在按预期工作。

关于javascript - Cordova 插件文件传输 : How do you upload a file to S3 using a signed URL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31009181/

相关文章:

android - 在 Android 中的 Facebook 登录期间仅获取 jsonObject 中的 ID 和名称

android - IBM Worklight 6.1 - 尝试构建 Android 环境时出现 "Missing .project file"错误

android - 如何在 phonegap 中使用插件来改变屏幕方向?

ios - 如何在 build.json 中指定 Cordova 构建目标

javascript - 跨浏览器目录上传方法

javascript - 使用 slider 值动态更新 Javascript 中的条形图

javascript - Jquery promise 链

javascript - 如何设置复选框中的选中值

android - 如何在AChartEngine中获取折线图上的可见点数

Windows Universal 应用程序在将身份与商店关联后崩溃