在 IE7 中使用 Prawn 生成 Rails PDF

发布于 2024-08-08 02:37:13 字数 1164 浏览 10 评论 0原文

我正在使用 Prawn 和 Prawnto 在 Ruby on Rails 应用程序(Rails 版本 2.2.2)中生成 PDF,该应用程序运行良好,可以愉快地生成 PDF 并将其发送给用户以在 Firefox 中下载。

问题出在IE7上。

我有一个像这样设置的路线:

map.invoice_pdf '/invoices.pdf', :controller => 'invoices', 
                :action => 'index', :format => 'pdf'

然后我有一个像这样的链接可以调用:

invoice_pdf_path(:year => params[:year], :month => params[:month], 
                 :unpaid_only => params[:unpaid_only])

在我的控制器中如下:

 def index
    params[:year]  = default params[:year]
    params[:month] = default params[:month]
    params[:page] ||= 1

    @invoices = Arobl.find_invoices_for_customer(current_customer.strCustomerID,
                       params)

    respond_to do |format|
      format.html{ render :action => 'index' }
      format.pdf{
        prawnto :inline => false, :filename => 
                "#{current_customer.strCustomerID}_invoice.pdf"
  end

在 FF 中,这按预期工作,当单击链接时,会以 .pdf 格式调用显示操作,并以正确命名的 PDF 进行响应。当使用 IE7 时,它会说找不到文件或网站,并引用“invoices.pdf”而不是预期的 customer_id_invoice.pdf 文件名。

知道什么可能导致这种行为吗?

谢谢!

I'm using Prawn and Prawnto to generate a PDF in a Ruby on Rails app (Rails version 2.2.2) which works great and generates PDFs happily and sends them to the user to download in Firefox.

The problem is in IE7.

I have a route set up like so:

map.invoice_pdf '/invoices.pdf', :controller => 'invoices', 
                :action => 'index', :format => 'pdf'

Which I then have a link like so to call:

invoice_pdf_path(:year => params[:year], :month => params[:month], 
                 :unpaid_only => params[:unpaid_only])

And the following in my controller:

 def index
    params[:year]  = default params[:year]
    params[:month] = default params[:month]
    params[:page] ||= 1

    @invoices = Arobl.find_invoices_for_customer(current_customer.strCustomerID,
                       params)

    respond_to do |format|
      format.html{ render :action => 'index' }
      format.pdf{
        prawnto :inline => false, :filename => 
                "#{current_customer.strCustomerID}_invoice.pdf"
  end

In FF this works as expected, when the link is clicked the show action is invoked with a format of .pdf, and responds with the correctly named PDF. When it's hit with IE7 it says that the file or website could not be found, and references "invoices.pdf" instead of the expected customer_id_invoice.pdf filename.

Any idea what could be causing this behaviour?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

圈圈圆圆圈圈 2024-08-15 02:37:13

我也有这个问题。当我尝试在 Internet Explorer(7 或 8)上请求没有 SSL 的相同 PDF 时,它可以工作,但如果我使用 SSL 请求它,它就不起作用...

我们认为我们可能已经追踪到 IE 的标头下载 PDF 时期待。我还没有检查 prawnto 源代码来查看它设​​置了什么标头,但我们很可能会使用一些 Rack Middleware 来注入我们需要的标头:

# add headers for PDF downloads in IE
# PDFs not downloading correctly via SSL in IE
# solution: add some headers for PDF downloads
# http://marc.info/?l=php-general&m=124301243808544&w=2
class RackAddPdfHeadersForIe
  def initialize( app )
    @app = app
  end

  def call( env )
    @status, @headers, @body = @app.call env
    add_headers if is_pdf? and is_internet_explorer?        
    [@status, @headers, @body]
  end

  def is_pdf?
    @headers['Content-Type'] =~ /pdf/
  end

  def is_internet_explorer?
    @headers['User-Agent'] =~ /MSIE ([0-9]{1,}[\.0-9]{0,})/
  end

  def add_headers
    @headers['Content-Description'] = 'File Transfer'
    @headers['Content-Transfer-Encoding'] = 'binary'
    @headers['Expires'] = '0'
    @headers['Pragma'] = 'public'
  end      
end

所以我尝试了这个,认为它会起作用,然后发现它确实仍然没有不工作。

所以我最终这样做了,无论出于什么原因,这对我有用:

class ReportsController < ApplicationController

  def payroll_summary
    respond_to do |format|
      format.pdf do 
        response.headers['Content-Disposition'] = "attachment;filename=\"#{action_name}.pdf\""
        response.headers['Content-Description'] = 'File Transfer'
        response.headers['Content-Transfer-Encoding'] = 'binary'
        response.headers['Expires'] = '0'
        response.headers['Pragma'] = 'public'
        render
      end  #format.pdf
    end #respond_to
  end #payroll_summary

end

I'm having this problem as well. When I try to request the same PDF without SSL on Internet Explorer (7 or 8) it works, but if I request it with SSL, it doesn't work...

We think we may have tracked this down to headers that IE is expecting when downloading a PDF. I haven't checked the prawnto source code to see what headers it set, but we are likely going to use some Rack Middleware to inject the headers we need:

# add headers for PDF downloads in IE
# PDFs not downloading correctly via SSL in IE
# solution: add some headers for PDF downloads
# http://marc.info/?l=php-general&m=124301243808544&w=2
class RackAddPdfHeadersForIe
  def initialize( app )
    @app = app
  end

  def call( env )
    @status, @headers, @body = @app.call env
    add_headers if is_pdf? and is_internet_explorer?        
    [@status, @headers, @body]
  end

  def is_pdf?
    @headers['Content-Type'] =~ /pdf/
  end

  def is_internet_explorer?
    @headers['User-Agent'] =~ /MSIE ([0-9]{1,}[\.0-9]{0,})/
  end

  def add_headers
    @headers['Content-Description'] = 'File Transfer'
    @headers['Content-Transfer-Encoding'] = 'binary'
    @headers['Expires'] = '0'
    @headers['Pragma'] = 'public'
  end      
end

So I tried this, thought it would work, then found that indeed it still didn't work.

So I ended up doing this, for whatever reason, this worked for me:

class ReportsController < ApplicationController

  def payroll_summary
    respond_to do |format|
      format.pdf do 
        response.headers['Content-Disposition'] = "attachment;filename=\"#{action_name}.pdf\""
        response.headers['Content-Description'] = 'File Transfer'
        response.headers['Content-Transfer-Encoding'] = 'binary'
        response.headers['Expires'] = '0'
        response.headers['Pragma'] = 'public'
        render
      end  #format.pdf
    end #respond_to
  end #payroll_summary

end
以歌曲疗慰 2024-08-15 02:37:13

中解释了此 ie 问题

http://support.microsoft.com/kb/323308 解决方案是将 Cache-Control 标头设置为除 no-store 之外的其他内容,例如:

response.headers["Cache-Control"] = "private, max-age=0, must-revalidate"

更多人可能会遇到此问题,因为 Rails 2.3.6+ 似乎将 Cache-Control 设置为 no-store,而早期版本没有这样做。

This ie issue is explained in http://support.microsoft.com/kb/323308

The solution is to set your Cache-Control header to something other than no-store with something like:

response.headers["Cache-Control"] = "private, max-age=0, must-revalidate"

More people are likely to run into this as rails 2.3.6+ seems to set Cache-Control to no-store where earlier versions didn't.

墟烟 2024-08-15 02:37:13

作为临时解决方案,我使用了此处记录的方法: http://chelsearobb.wordpress.com/2009/09/09/ saving-a-prawn-pdf-to-file/ 并在本地保存文件,使用 send_data 和 File.read,然后删除该文件,该文件似乎在所有浏览器中都能正常工作。

我仍然好奇为什么它在 IE7 之前不起作用。

As an interim solution, I used the approach documented here: http://chelsearobb.wordpress.com/2009/09/09/saving-a-prawn-pdf-to-file/ and just save the file locally, use send_data and a File.read, and then delete the file which seems to work fine in all browsers.

I'm still curious as to why it wouldn't work in IE7 previously though.

救星 2024-08-15 02:37:13

我将问题归结为 prawnto 的compile_support.rb 文件。

  # added to make ie happy with ssl pdf's (per naisayer)
  def ssl_request?
    @controller.request.env['SERVER_PROTOCOL'].downcase == "https"
  end

我们看到 apache 的 SERVER_PROTCOL 环境变量始终设置为 HTTP/1.1,即使使用 https 时也是如此。什么时候需要 ssl_required?为 false,这是来自 ie 的请求,虾将设置 Pragma="no-cache"。这就是导致我们出现问题的原因。

如果您的应用程序仅使用 https,您可以更改此函数以始终返回 true。如果这还不够,你可以编写一个 apache 指令,如下所示:

SetEnv SERVER_PROTOCOL "https"

我把它放在我的 ssl.conf 文件中,现在一切都按预期工作。

I chased my issue down to prawnto's compile_support.rb file.

  # added to make ie happy with ssl pdf's (per naisayer)
  def ssl_request?
    @controller.request.env['SERVER_PROTOCOL'].downcase == "https"
  end

We were seeing that apache's SERVER_PROTCOL env variable was always set to HTTP/1.1 even when using https. When ssl_required? is false and it's a request from ie prawnto will set Pragma="no-cache". This is what was causing our issues.

If your app only uses https you can change this function to always return true. If this isn't enough you can write an apache directive along the lines of:

SetEnv SERVER_PROTOCOL "https"

I put this right in my ssl.conf file and everything now works as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文