Rails 7.0中send_data无法在新标签页打开PDF的问题
问题原因及解决方法
核心问题
Rails 7默认启用了Turbo,你用button_to生成的是POST表单,Turbo会自动拦截这个请求并以TURBO_STREAM格式处理,但你的openPDF动作返回的是PDF二进制数据,Turbo无法解析这种非HTML/Turbo Stream的响应,所以没法在新标签页正常打开。而把代码移到index动作时,你是直接通过GET请求访问(没有Turbo拦截),所以能正常显示PDF。
解决方法
有两种简单的修复方式:
方式1:禁用Turbo并指定新标签页打开
给button_to添加data: { turbo: false },让浏览器用原生方式处理这个POST请求,同时加上target: "_blank"指定在新标签页打开:
<%= button_to 'Open', welcome_openPDF_path(pdf_file: file), method: :post, data: { turbo: false }, target: "_blank" %>
方式2:改用GET请求(更适合资源获取场景)
如果你的PDF文件路径不需要保密,建议改用GET请求,直接用link_to更符合REST规范,同时路由也要改成GET:
- 修改
routes.rb:
get 'welcome/openPDF'
- 修改视图代码:
<%= link_to 'Open', welcome_openPDF_path(pdf_file: file), target: "_blank" %>
重要安全提醒
你当前的open(params[:pdf_file])存在严重的目录遍历攻击风险,攻击者可以通过构造pdf_file参数访问服务器上任意文件(比如../../../../etc/passwd)。必须限制文件的访问范围,比如只允许访问public/pdfs目录下的文件:
def openPDF # 限定文件在指定目录内 allowed_dir = Rails.root.join('public', 'pdfs') safe_path = allowed_dir.join(params[:pdf_file]).cleanpath # 验证路径是否在允许的目录范围内 unless safe_path.absolute? && safe_path.starts_with?(allowed_dir) raise ActionController::RoutingError, 'Not Found' end data = open(safe_path, 'rb').read send_data(data, type: 'application/pdf', filename: params[:pdf_file], disposition: 'inline') end
内容的提问来源于stack exchange,提问作者sergio folco
相关产品推荐
相关产品推荐

