如何使用来自 AJAX 帖子的 Rails send_data 触发下载

Posted

技术标签:

【中文标题】如何使用来自 AJAX 帖子的 Rails send_data 触发下载【英文标题】:How to trigger download with Rails send_data from AJAX post 【发布时间】:2013-04-20 23:27:19 【问题描述】:

我正在尝试使用 send_data 返回一个 PNG 图像作为 ajax 发布请求的响应。如何让浏览器在成功回调时触发下载?

详情

我正在使用canvas.toDataURL() 生成一个大型 base64 图像,然后将其发布到 Rails (v3.2.6)。 Rails 将其解码为二进制 PNG,并将图像发送回客户端。

我也试过send_file,但也有同样的问题。

其他选项

    下载图像客户端:我们不能这样做,因为 (1) Safari crashes on large base64 URLs 和 (2) Safari does not yet support the download attribute on anchor tags 我需要指定下载的图像文件名。

    使用$.get 代替$.post 我们不能这样做,因为我们需要将canvas.toDataURL() 与请求一起发送到服务器。 GET 请求 URI 有大小限制。

【问题讨论】:

然后将来自 AJAX 请求的数据放入会话中,然后通过 location.href="..." 指向发送适当标头的脚本触发下载,从会话中传递数据,然后将其删除来自会话。 不确定为什么要使用 AJAX 请求来下载文件。尊重 send_data/send_file 操作的非 AJAX link_to 应该下载图像。 我认为这是一个关于如何将数据下载为文件的http标准。也许使用 content_type: 'image/png' ? 我不得不做同样类型的事情,最后只是解码和保存图像服务器端,然后在 javascript 中使用 window.open 打开一个窗口,该窗口使用服务器中的 send_file 来获取图像,然后只需删除服务器上的临时图像。 【参考方案1】:

在控制器中创建一个函数

def ajax_download
  send_file "path_to_file/" + params[:file]
end

然后在控制器动作中

respond_to do |format|
  @java_url = "/home/ajax_download?file=#file_name"
  format.js render :partial => "downloadFile"
end

并使用 _downloadFile.js.erb 创建部分视图文件夹名称并写下这一行

window.location.href = "<%=@java_url %>"

【讨论】:

您可能想要制作一个 iframe 并将其位置设置为文件的 URL。无论哪种方式,这都是一个可靠的解决方案。 @mayatron 请批准这个 在这里为我工作:) 值得一提的是,在send_file 中使用params[:file] 是未经处理的,可能会导致数据被盗。【参考方案2】:

您不能从 JS 下载文件到磁盘。这是一个安全问题。请参阅下面的博客文章了解一个很好的解决方法。

http://johnculviner.com/post/2012/03/22/Ajax-like-feature-rich-file-downloads-with-jQuery-File-Download.aspx

【讨论】:

您可以将画布图像下载为 base64,只要图像没有被污染。这有一些限制,例如设置文件名。工作示例:greenethumb.com/article/1429/…【参考方案3】:

不要不要只是复制并粘贴已接受的答案。这是一个不可低估的巨大安全风险。尽管这项技术很聪明,但根据任何人都可以输入的参数来传递文件,就可以访问任何人可以想象到的任何文件。

这是使用相同技术的更安全方法的示例。它假设有一个登录的用户拥有 API 令牌,但您应该能够根据自己的场景调整它。

在行动中:

current_user.pending_download = file_name
current_user.save!
respond_to do |format|
  @java_url = "/ajax_download?token=#current_user.api_token"
  format.js render :partial => "downloadFile"
end

在控制器中创建一个函数

def ajax_download
  if params[:token] == current_user.api_token
    send_file "path_to_file/" + current_user.pending_download
    current_user.pending_download = ''
    current_user.save!
  else
    redirect_to root_path, notice: "Unauthorized"
  end
end

使用 _downloadFile.js.erb 创建部分视图文件夹名称

window.location.href = "<%=@java_url %>"

当然,您需要一条指向/ajax_download in routes.rb 的路由

get 'ajax_download', to: 'controller#ajax_download'

【讨论】:

以上是关于如何使用来自 AJAX 帖子的 Rails send_data 触发下载的主要内容,如果未能解决你的问题,请参考以下文章

Rails Ajax - 渲染不同的部分

判断帖子是不是来自codeigniter中的ajax调用的方法?

如何在 rspec rails 请求测试中发布缺少authentity_token 的帖子?

php 忽略来自ajax调用的粘性帖子

如何在 Rails 视图中呈现所有评论?

通过colorbox提交Ajax帖子后更新div?