[英]cordova-plugin-file-transfer: How do you upload a file to S3 using a signed URL?
I am able to upload to S3 using a file picker and regular XMLHttpRequest
(which I was using to test the S3 setup), but cannot figure out how to do it successfully using the cordova file transfer plugin. 我可以使用文件选择器和常规
XMLHttpRequest
(用于测试S3设置)将其上传到S3,但无法弄清楚如何使用cordova文件传输插件成功完成此操作。
I believe it is either to do with the plugin not constructing the correct signable request, or not liking the local file uri given. 我认为这与该插件未构造正确的可签名请求有关,或者与该给定的本地文件uri不相关。 I have tried playing with every single parameter from headers to uri types, but the docs aren't much help, and the plugin source is bolognese.
我已经尝试过处理从标头到uri类型的每个参数,但是文档并没有太大帮助,并且插件来源是bolognese。
The string the request needs to sign match is like: 请求需要签名匹配的字符串如下:
PUT
1391784394
x-amz-acl:public-read
/the-app/317fdf654f9e3299f238d97d39f10fb1
Any ideas, or possibly a working code example? 有什么想法,或者可能是一个有效的代码示例?
A bit late, but I just spent a couple of days struggling with this so in case anybody else is having problems, this is how managed to upload an image using the javascript version of the AWS SDK to create the presigned URL. 有点晚了,但是我花了几天时间来解决这个问题,以防万一其他人遇到问题,这就是如何使用AWS开发工具包的javascript版本上载图像来创建预签名URL的方法。
The key to solving the problem is in the StringToSign
element of the XML SignatureDoesNotMatch
error that comes back from Amazon. 解决此问题的关键是从亚马逊返回的XML
SignatureDoesNotMatch
错误的StringToSign
元素。 In my case it looked something like this: 就我而言,它看起来像这样:
<StringToSign>
PUT\n\nmultipart/form-data; boundary=+++++org.apache.cordova.formBoundary\n1481366396\n/bucketName/fileName.jpg
</StringToSign>
When you use the aws-sdk
to generate a presigned URL for upload to S3, internally it will build a string based on various elements of the request you want to make, then create an SHA1 hash of it using your AWS secret. 当您使用
aws-sdk
生成要上传到S3的预签名URL时,它将在内部基于您要发出的请求的各种元素构建一个字符串,然后使用您的AWS密钥为其创建SHA1哈希。 This hash is the signature that gets appended to the URL as a parameter, and what doesn't match when you get the SignatureDoesNotMatch
error. 此哈希是作为参数附加到URL的签名,当您收到
SignatureDoesNotMatch
错误时,该SignatureDoesNotMatch
不匹配。
So you've created your presigned URL, and passed it to cordova-plugin-file-transfer
to make your HTTP request to upload a file. 因此,您已经创建了预签名的URL,并将其传递给
cordova-plugin-file-transfer
以发出HTTP请求来上传文件。 When that request hits Amazon's server, the server will itself build a string based on the request headers etc, hash it and compare that hash to the signature on the URL. 当该请求到达Amazon服务器时,服务器本身将根据请求标头等构建一个字符串,对其进行哈希处理并将该哈希与URL上的签名进行比较。 If the hashes don't match then it returns the dreaded...
如果哈希值不匹配,则返回可怕的...
The request signature we calculated does not match the signature you provided. Check your key and signing method.
The contents of the StringToSign
element I mentioned above is the string that the server builds and hashes to compare against the signature on the presigned URL. 我上面提到的
StringToSign
元素的内容是服务器构建并哈希以与预签名URL上的签名进行比较的字符串。 So to avoid getting the error, you need to make sure that the string built by the aws-sdk
is the same as the one built by the server. 因此,为避免出现错误,您需要确保
aws-sdk
构建的字符串与服务器构建的字符串相同。
After some digging about, I eventually found the code responsible for creating the string to hash in the aws-sdk
. 经过一番探索,我最终找到了负责创建要哈希到
aws-sdk
的字符串的代码。 It is located (as of version 2.7.12) in: 它位于(自2.7.12版本起)位于:
node_modules/aws-sdk/lib/signers/s3.js
Down the bottom at line 168 there is a sign
method: 在第168行底部,有一个
sign
方法:
sign: function sign(secret, string) { return AWS.util.crypto.hmac(secret, string, 'base64', 'sha1'); }
If you put a console.log
in there, string
is what you're after. 如果在其中放置
console.log
,则string
是您要使用的。 Once you make the string
that gets passed into this method the same as the contents of StringToSign
in the error message coming back from Amazon, the heavens will open and your files will flow effortlessly into your bucket. 一旦使传递到此方法的
string
与从亚马逊返回的错误消息中的StringToSign
的内容相同,天堂就会打开,您的文件将毫不费力地流入您的存储桶。
On my server running node.js, I originally created my presigned URL like this: 在运行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
This produced a signing string like this, similar to the OP's: 这产生了一个类似于OP的签名字符串:
PUT
1481366396
/bucketName/fileName.jpg
On the client side, I used this presigned URL with cordova-plugin-file-transfer
like so (I'm using Ionic 2 so the plugin is wrapped in their native wrapper): 在客户端,我将此预签名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);
});
Running the code produced the signature doesn't match error, and the string in the <StringToSign>
element looks like this: 运行生成的代码,签名不匹配错误,并且
<StringToSign>
元素中的字符串如下所示:
PUT
multipart/form-data; boundary=+++++org.apache.cordova.formBoundary
1481366396
/bucketName/fileName.jpg
So we can see that cordova-plugin-file-transfer
has added in its own Content-Type
header which has caused a discrepancy in the signing strings. 因此,我们可以看到
cordova-plugin-file-transfer
已在其自己的Content-Type
标头中添加,这导致了签名字符串的差异。 In the docs relating to the options object that get passed into the upload method it says: 在与options对象相关的文档中 ,该文档传递到upload方法中,它说:
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)
so basically, if no Content-Type
header is set it will default to multipart form data. 因此,基本上,如果未设置
Content-Type
标头,则默认为多部分表单数据。
Ok so now we know the cause of the problem, it's a pretty simple fix. 好的,现在我们知道了问题的原因,这是一个非常简单的修复。 On the server side I added a
ContentType
to the params
object passed to the S3 getSignedUrl
method: 在服务器端,我将
ContentType
添加到传递给S3 getSignedUrl
方法的params
对象中:
var params = {
Bucket: 'bucketName',
Key: imageName,
Expires: 60,
ContentType: 'image/jpeg' // <---- content type added here
};
and on the client added a headers
object to the options
passed to cordova-plugin-file-transfer
's upload method: 和客户端上添加一个
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',
}
};
and hey presto! 嘿,presto! The uploads now work as expected.
现在可以正常进行上传。
I run into such issues with this plugin 我在这个插件中遇到了这样的问题
The only working way I found to upload a file with a signature is the method of Christophe Coenraets : http://coenraets.org/blog/2013/09/how-to-upload-pictures-from-a-phonegap-app-to-amazon-s3/ 我发现上传带有签名的文件的唯一可行方法是Christophe Coenraets的方法: http ://coenraets.org/blog/2013/09/how-to-upload-pictures-from-a-phonegap-app- 到亚马逊-S3 /
With this method you will be able to upload your files using the cordova-plugin-file-transfer 使用此方法,您将可以使用cordova-plugin-file-transfer上载文件
First, I wanted to use the aws-sdk on my server to sign with getSignedUrl() It returns the signed link and you only have to upload to it. 首先,我想使用服务器上的aws-sdk与getSignedUrl()进行签名,它返回已签名的链接,而您只需要上传到该链接即可。
But, using the plugin it always end with 403 : signatures don't match 但是,使用插件时,它总是以403结尾:签名不匹配
It may be related to the content length parameter but I didn't found for now a working solution with aws-sdk and the plugin 它可能与content length参数有关,但是我暂时没有找到可使用aws-sdk和插件的解决方案
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.