我尝试使用DropzoneJS向S3进行无服务器上传。我特意在AWS预先指定的网址上遇到问题,表明x-amz-acl
标头未签名。
使用Javascript:
var dz = new Dropzone("div#upload", {
url: "tbd",
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 2, // MB
accept: this.getUploadUrl,
method: 'put',
sending: function(file, xhr) {
var _send = xhr.send;
xhr.setRequestHeader('x-amz-acl', 'public-read');
xhr.send = function() {
_send.call(xhr, file);
}
},
});
dz.on('processing', function(file) {
// change url before sending
this.options.url = file.uploadUrl;
});
function getUploadUrl(file, cb) {
var params = {
fileName: file.name,
fileType: file.type,
};
$.getJSON('signput.php', params).done(function(data) {
var decodedUri = decodeURIComponent(data['signedRequest']);
if (!data.signedRequest) {
return cb('Failed to receive an upload url');
}
console.log(decodedUri);
file.uploadUrl = decodedUri;
cb();
}).fail(function() {
return cb('Failed to receive an upload url');
});
}
PHP(调用以获得预先签名的URL):
$fileName = $_GET['fileName'];
$s3Client = new Aws\S3\S3Client([
'version' => '2006-03-01',
'region' => 'us-west-2',
'credentials' => [
'key' => '__MY__KEY__',
'secret' => '__MY__SECRET__',
],]);
$cmd = $s3Client->getCommand('PutObject', [
'Bucket' => '__MY__BUCKET__',
'Key' => $fileName
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes');
// Get the actual presigned-url
$url = (string) $request->getUri();
$urlArray['signedRequest'] = $url;
$urlArray = json_encode($urlArray);
echo $urlArray;
我还尝试在Dropzone标头和S3 getCommand中将x-amz-acl
设置为公开读取,但它无效。
我得到的错误:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code>
<Message>There were headers present in the request which were not signed</Message>
<HeadersNotSigned>x-amz-acl</HeadersNotSigned>
</Error>
答案 0 :(得分:1)
有一个问题 - 我需要将ACL => 'public-read'
从JS代码移到签名请求中。
Dropzone发送功能变为:
sending: function(file, xhr) {
var _send = xhr.send;
xhr.send = function() {
_send.call(xhr, file);
}
}
PHP签名请求变成:
$cmd = $s3Client->getCommand('PutObject', [
'Bucket' => '__MY__BUCKET__',
'Key' => $fileName,
'ACL' => 'public-read'
]);
感谢Michael指出我正确的方向。
最终代码供参考......
使用Javascript:
var dz = new Dropzone("div#upload", {
url: "tbd",
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 2, // MB
accept: this.getUploadUrl,
method: 'put',
sending: function(file, xhr) {
var _send = xhr.send;
xhr.send = function() {
_send.call(xhr, file);
}
},
});
dz.on('processing', function(file) {
// change url before sending
this.options.url = file.uploadUrl;
});
function getUploadUrl(file, cb) {
var params = {
fileName: file.name,
fileType: file.type,
};
$.getJSON('signput.php', params).done(function(data) {
var decodedUri = decodeURIComponent(data['signedRequest']);
if (!data.signedRequest) {
return cb('Failed to receive an upload url');
}
file.uploadUrl = decodedUri;
cb();
}).fail(function() {
return cb('Failed to receive an upload url');
});
}
PHP:
$fileName = $_GET['fileName'];
$s3Client = new Aws\S3\S3Client([
'version' => '2006-03-01',
'region' => 'us-west-2',
'credentials' => [
'key' => '__MY_KEY__',
'secret' => '__MY_SECRET__,
],]);
$cmd = $s3Client->getCommand('PutObject', [
'Bucket' => '__MY_BUCKET__',
'Key' => $fileName,
'ACL' => 'public-read'
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes');
// Get the actual presigned-url
$url = (string) $request->getUri();
$urlArray['signedRequest'] = $url;
$urlArray = json_encode($urlArray);
echo $urlArray;