javascript - 直接访问 Amazon S3 被拒绝

标签 javascript perl amazon-s3 jquery-file-upload

我正在使用 http://pjambet.github.io/blog/direct-upload-to-s3/作为教程。我已经启用了 CORS(请参阅 CORS 文件)。我得到了 JSON 响应,这在文件上传查询的函数中很好(在添加中)。失败发生在获得签名和策略之后。当尝试实际上传文件时,我收到来自亚马逊的拒绝访问错误。文件不上传。我错过了什么吗?

HTML:

<form class="file_upload" action="https://<% $AWSBUCKET %>.s3.amazonaws.com" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" />
<input type="hidden" name="policy" />
<input type="hidden" name="signature" />
<input type="hidden" name="AWSAccessKeyId" value="<% $AWSACCESS %>" />
<input type="hidden" name="acl" value="public-read" />
<input type="hidden" name="success_action_status" value="201" />

<div class="fileupload-content">
  <div class="fileupload-progress">
  </div>
</div>
<div class="file-upload">
  <span class="btn btn-success fileinput-button">
    <i class="glyphicon glyphicon-plus"></i>
    <span>Select files...</span>
    <input type="file" name="file" multiple>
  </span>
  <div class="progress progress-striped active">
    <div class="bar">
  </div>
</div>

Javascript:

$(function() {
  $('.file_upload').each(function() {
    var form = $(this)
    $(this).fileupload({
      url: form.attr('action'),
      type: 'POST',
      autoUpload: true,
      dataType: 'xml', // This is really important as s3 gives us back the url of the file in a XML document
      add: function (event, data) {
        $.ajax({
          url: "s3signed.html",
          type: 'GET',
          dataType: 'json',
          data: {filename: data.files[0].name, max_file_size : <% $MAX_FILE_SIZE %>}, // send the file name to the server so it can generate the key param
          async: false,
          success: function(data) {
            // Now that we have our data, we update the form so it contains all
            // the needed data to sign the request
            form.find('input[name=key]').val(data.key)
            form.find('input[name=policy]').val(data.policy)
            form.find('input[name=signature]').val(data.signature)
            console.log(data.key);
            console.log(data.policy);
            console.log(data.signature);
          }
        })
        data.submit();
      },
      send: function(e, data) {
        $('.progress').fadeIn();
      },
      progress: function(e, data){
        // This is what makes everything really cool, thanks to that callback
        // you can now update the progress bar based on the upload progress
        var percent = Math.round((e.loaded / e.total) * 100)
        $('.bar').css('width', percent + '%')
      },
      fail: function(e, data) {
        console.log('fail');
        console.log(data);
        console.log(e);
      },
      success: function(data) {
        // Here we get the file url on s3 in an xml doc
        var url = $(data).find('Location').text()

        $('#real_file_url').val(url) // Update the real input in the other form
      },
      done: function (event, data) {
        $('.progress').fadeOut(300, function() {
          $('.bar').css('width', 0)
        })
      },
    })
  })
});

Perl:

use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
use MIME::Base64;

use Data::Uniqid qw ( uniqid );
my $uniqid = uniqid;

my $key = "upload/$uniqid/$filename";
my $policy = s3PolicyDocument($AWSBUCKET, $max_file_size, $key);
my $signature = s3Signature($AWSSECRET, $policy);

my %response = (
  policy => $policy,
  signature => $signature,
  key => $key,
  success_action_status => 201
);

use JSON;
print JSON::encode_json(\%response);

sub s3PolicyDocument {
  my ($AWSBUCKET, $max_file_size, $key) = @_;
  use DateTime;
  my $dt = DateTime->now;
  $dt->add(minutes => 30);

  my $policy = '{"expiration": "'.$dt.'",
    "conditions": [ 
      {"bucket": "'.$AWSBUCKET.'"}, 
      {"acl": "public-read"},
      ["starts-with", "$key", ""],
      ["starts-with", "$Content-Type", ""],
      ["starts-with", "$name", ""],
      ["starts-with", "$Filename", ""],
      ["content-length-range", 0, '.$max_file_size.'],
      {"success_action_status": "201"},
    ]
  }';

  use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
  use MIME::Base64;


  $policy = encode_base64($policy);
  $policy =~ s/\n//g;
  return $policy;
}

sub s3Signature {
  my($AWSSECRET, $policy) = @_;
  my $signature = encode_base64(hmac_sha1($policy, $AWSSECRET));
  $signature =~ s/\n//g;
  return $signature;
}

CORS:

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

亚马逊回复:

<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>2448EA4E8E1F5377</RequestId>
<HostId>NlbqOAnjhPnqQLpaJRY1cVC6nFJ3ziVK+7ENrgILhA2njekXnp4mowv7jyTE2Z7K</HostId>
</Error>

最佳答案

根据跨站点上传的文档,您应该使用 forceIframeTransport选项。

$(this).fileupload({
    forceIframeTransport : true,
    ...
});

关于javascript - 直接访问 Amazon S3 被拒绝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21183358/

相关文章:

windows - 我怎样才能使 Perl 的 system() 不阻塞?

mysql - 如何在 Perl 脚本中为 MySQL 设置变量和过程变量

amazon-s3 - 从 terraform 在 AWS S3 中上传多个文件

amazon-web-services - 连接到 S3 存储桶时如何保护 AWS 中的凭证

javascript - 为什么 HTML 验证在 Electron 中不起作用?

javascript - Jquery删除文本中的空格

linux - 在 Perl 中对类似十六进制的字符串执行算术运算

javascript - getJSON 在单击按钮时不起作用,但在按 Enter 键时起作用

JavaScript - 无法检查空值

python-3.x - 如何根据文件修改日期从 s3 存储桶下载文件?