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

Rails 7如何从二进制字符串直接下载PDF(无需存服务器)

Rails 7 实现无服务器存储的PDF下载功能

我在Rails 7应用中使用外部服务生成PDF,需要发送GET请求获取PDF,响应返回Base64编码字符串。现在想实现无需将文件存储在服务器上就让用户下载的功能,有没有现代实现方式或者相关gem?我找到的方案都要存文件,但实际测试没触发下载,还报错了。


现有代码

PDF处理服务类

# 用于处理PDF编码字符串的服务类
class PdfGenerator
  def initialize(binary_pdf)
    @binary_pdf = binary_pdf
  end

  attr_reader :binary_pdf
  
  def call
    File.open('invoice.pdf', 'wb') do |file|
      content = Base64.decode64(binary_pdf)
      file << content
    end
  end
end

控制器代码

# payments_controller.rb
def pdf_download
  response = client.invoice_pdf(payment_id: params[:id]) # 发送GET请求获取PDF
  PdfGenerator.new(response[:invoice_pdf]).call
end

视图调用代码

<%= link_to t('.pdf_download'), pdf_download_payment_path(payment.id), data: { 'turbo-method' => :post } %>

遇到的错误

服务器返回日志:

No template found for PaymentsController#pdf_download, rendering head :no_content
Completed 204 No Content in 8ms (ActiveRecord: 0.2ms | Allocations: 2737)


现代实现方案(无需服务器存储)

直接利用Rails内置的send_data方法处理编码内容,通过响应头触发浏览器下载,完全不需要生成服务器本地文件:

修改控制器代码

# payments_controller.rb
def pdf_download
  # 获取外部服务返回的Base64编码PDF字符串
  pdf_base64 = client.invoice_pdf(payment_id: params[:id])[:invoice_pdf]
  # 解码Base64得到二进制PDF内容
  pdf_content = Base64.decode64(pdf_base64)

  # 设置响应参数,触发浏览器下载
  send_data(
    pdf_content,
    filename: "invoice_#{params[:id]}.pdf", # 自定义下载文件名,避免重复
    type: 'application/pdf', # 指定MIME类型
    disposition: 'attachment' # 强制触发下载,而非在浏览器内打开
  )
end

简化视图调用

如果路由配置为GET请求,可去掉data: { turbo-method: :post }:

<%= link_to t('.pdf_download'), pdf_download_payment_path(payment.id) %>

关键说明

  • send_data是Rails原生方法,直接将二进制内容发送给客户端,无需写入服务器文件系统
  • disposition: 'attachment'是核心配置,确保浏览器识别为下载文件而非在线预览
  • 自定义文件名建议加入唯一标识(比如支付ID),避免用户多次下载时出现文件名冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:46:08