You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7 Turbo Stream POST请求中send_data无法触发文件下载

问题描述

上传文件修改后返回,响应能获取到blob但浏览器不触发下载。添加data-turbo="false"后功能正常,但希望保留使用Turbo Stream。

原因分析

Turbo 默认通过 XMLHttpRequest 处理表单提交(当请求类型为 TURBO_STREAM 时),而浏览器不会为 XHR 请求自动触发文件下载行为——哪怕响应头包含Content-Disposition: attachment,也只会返回 blob 数据,不会弹出下载框。

解决方案

通过 Turbo Stream 将文件数据传递到前端,用 JavaScript 手动触发下载。以下是具体实现步骤:

步骤1:修改控制器代码

不再直接用send_data返回文件,而是生成文件的 Base64 编码,通过 Turbo Stream 渲染一段触发下载的 JS 代码:

class HomeController < ApplicationController
  require 'rubyXL/convenience_methods'
  require 'base64' # 引入Base64模块

  def index
  end

  def generate
    workbook = RubyXL::Parser.parse(params[:file])
    worksheet = workbook[0]
    worksheet = workbook.add_worksheet('testSheet')
    
    # 生成文件数据并转Base64
    file_data = workbook.stream.read
    file_base64 = Base64.encode64(file_data)

    respond_to do |format|
      format.turbo_stream do
        render turbo_stream: turbo_stream.update('download-trigger', <<~HTML)
          <script>
            // 将Base64转回Blob
            const blob = new Blob([Uint8Array.from(atob("#{file_base64}"), c => c.charCodeAt(0))], { type: 'application/xlsx' });
            // 创建临时URL触发下载
            const url = URL.createObjectURL(blob);
            const downloadLink = document.createElement('a');
            downloadLink.href = url;
            downloadLink.download = "FileName.xlsx";
            document.body.appendChild(downloadLink);
            downloadLink.click();
            // 清理资源
            document.body.removeChild(downloadLink);
            URL.revokeObjectURL(url);
          </script>
        HTML
      end
    end
  end
end

步骤2:更新视图

在表单下方添加一个隐藏的容器,用于接收 Turbo Stream 推送的 JS 代码:

<%= form_with(url: generate_path) do |form| %>
  <div style="margin: 10px">
    <%= form.file_field :file %>
  </div>
  <div style="margin: 10px">
    <%= form.submit "Generate", style: "background: red; cursor: pointer"  %>
  </div>
<% end %>
<!-- 用于接收Turbo Stream的容器 -->
<div id="download-trigger"></div>
原理说明
  1. 控制器将生成的 Excel 文件转为 Base64 编码,嵌入到 Turbo Stream 的 HTML 响应中;
  2. Turbo 接收到响应后,会更新页面上的download-trigger容器,执行里面的 JavaScript;
  3. JS 代码将 Base64 转回 Blob,创建临时下载链接并触发点击,从而让浏览器弹出下载框。

内容的提问来源于stack exchange,提问作者Bouaik Lhoussaine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:33:12