Elixir / Phoenix:客户端/浏览器AJAX上传到S3

时间:2017-02-13 19:00:48

标签: ajax amazon-s3 elixir phoenix-framework

我的Elixir / Phoenix应用程序需要能够录制HTML5视频,允许用户查看他们录制的视频,然后通过AJAX将录制内容直接上传到S3进行存储,并向Elixir服务器发送POST以存储新上传的视频宾语。在Rails世界中,有关于如何实现这一目标的各种宝石和冗长的教程;什么是Elixir / Phoenix直接上传S3文件的简单方法?

2 个答案:

答案 0 :(得分:6)

我最终解决了这个问题。需要在S3帐户上进行设置,添加服务器端代码以及添加客户端代码。

S3设置

首先,您需要一个AWS账户和一个S3存储桶。创建存储桶。

在存储桶设置中 - >权限 - >公共访问设置,确保"阻止新的公共ACL和上传公共对象"和"删除通过公共ACL授予的公共访问权限#34;是检查。

然后在Permissions下 - >在CORS配置中,添加CORS配置以允许来自您站点的跨域浏览器请求,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedOrigin>http://localhost:4000</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
</CORSConfiguration>

(为您的网站可访问的每个来源指定一个<AllowedOrigin>语句,或者如果您不担心CORS安全性,请将AllowedOrigin设置为*。)

良好的卫生条件还包括设置只能访问此S3存储桶的IAM角色,以及仅允许您允许的特定操作。然后,在服务器设置步骤中,您将提供IAM角色的访问凭据,而不是您的AWS账户访问凭据。我在此处显示的代码中跳过了此步骤。

服务器侧

确保安装了ex_aws软件包和所有依赖项(注意版本,以避免使用无效的预分配网址的错误):

  # in mix.exs, in the deps list
  # Stay at 2.0 to avoid presigned url bug: https://github.com/ex-aws/ex_aws/issues/602
  {:ex_aws, "2.0.1"},
  # :arc S3 integration
  {:ex_aws_s3, "~> 2.0"},
  # required by :ex_aws
  {:sweet_xml, "~> 0.6"},

config/config.exs中,提供您的AWS访问凭据和S3设置:

config :ex_aws,
  access_key_id:     System.get_env("AWS_ACCESS_KEY_ID"),
  secret_access_key: System.get_env("AWS_SECRET_ACCESS_KEY"),
  region: "us-east-1",
  s3: [
    scheme: "https://",
    host: "s3.amazonaws.com",
    region: "us-east-1" ]

(要与Heroku兼容,我将敏感值存储在config/secrets.exs中设置的环境变量中,这些变量从Git仓库中排除。)

现在设置控制器操作,该操作呈现将在其上进行S3文件上载的页面。最小控制器操作可能如下所示:

def edit(conn, %{"id" => id}) do
  render conn, "edit.html", presigned_s3_url: presigned_s3_url(id)
end

defp presigned_s3_url(id) do
  bucket = System.get_env("S3_BUCKET")
  path = "uploads/interview_recordings/#{id}.webm"
  {:ok, url} = ExAws.S3.presigned_url(ExAws.Config.new(:s3), :put, bucket, path, 
    query_params: [
      # Set permissions so public can view this file
      {"x-amz-acl", "public-read"}, 
      {"contentType", "binary/octet-stream"}
    ]
  )
  url
end

此#edit操作提供了一个变量@presigned_s3_url,它授权我们的客户端代码将文件上传到S3。请注意调用:put时指定的ExAws.S3.presigned_url方法;如果您指定不同的请求方法或省略查询参数等,S3上传请求可能会被拒绝。您在此处指定的参数必须与实际AJAX请求的参数完全匹配,否则S3将拒绝上传,因为签名S3生成的符号与我们生成的签名不匹配。

客户端

您的设置会有所不同,因此我不会粘贴任何HTML标记。唯一重要的部分是:一些客户端操作(在我的情况下,记录HTML5视频)导致文件可供浏览器JS使用,并且当客户端点击&#34;提交&#34;按钮,我们向附带文件数据的已签名S3 url发出PUT请求。我的AJAX调用如下所示:

$('.js-submit-recording').click(function(e) {
  e.preventDefault();
  console.log("Uploading the recording to S3...");
  $.ajax({
    url: $(this).data('presigned-s3-url'), // the url we generated server-side
    type: "PUT",
    contentType: "binary/octet-stream",
    processData: false, // Treat the data as a raw file, not as a POST form
    data: recording_data, // a blob object
    success: function() {
      console.log("File successfully uploaded!");
      // Now you can initiate next steps like making a POST request to our
      // Phoenix server to record the newly uploaded file in our db
    },
    error: function() {
      console.log("File not uploaded :-/");
      console.log(arguments);
      // If you get errors, open Chrome's Network tab and look at the
      // response body for the S3 request. It will describe the reason / 
      // error and some details that can help with troubleshooting.
    }
  });
});

这应该让基础工作正常运作!

答案 1 :(得分:0)

基本上你需要阅读this教程。 您使用的只是Arc,并使用ex_aws。您必须在配置文件中添加s3的配置,并基本上使用Arc调整您的JS。

如果您不想在数据库中存储这些文件,请直接在代码中使用name_of_your_uploader.store。如果你想用AJAX这样做,你可以用频道来做。