当我尝试访问 Prawn 生成的 PDF 时,为什么 Net::HTTP 超时?

发布于 2024-12-21 06:26:26 字数 1714 浏览 2 评论 0原文

我正在使用 Prawn 从我的控制器生成 PDF,当直接通过 url 访问时,它可以完美地工作,IE localhost:3000/responses/1.pdf

但是,当我尝试动态生成此文件以包含在梅勒,一切都冻结了并且超时了。

我尝试了各种生成/附加文件的方法,但都没有改变结果。

我还尝试修改 Net::HTTP 的超时,但没有效果,只是需要更长的时间才能超时。

如果我在 Rails 控制台上运行此命令,我会收到 PDF 数据流。

Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000)

但是如果我在控制器中包含此代码,则会超时。

我尝试了两种不同的方法方法,但都反复失败。

方法1 控制器:

http = Net::HTTP.new('localhost', 3000)
http.read_timeout = 6000
file = http.get(response_path(@response, :format => 'pdf')) #timeout here
ResponseMailer.confirmComplete(@response,file).deliver #deliver the mail!

方法 1 邮件程序:

def confirmComplete(response,file)
  email_address = response.supervisor_id
  attachments["test.pdf"] = {:mime_type => "application/pdf", :content=> file}
  mail to: email_address, subject: 'Thank you for your feedback!'
end

以上代码超时。

方法 2 控制器:

ResponseMailer.confirmComplete(@response).deliver #deliver the mail!

方法 2 邮件程序:

def confirmComplete(response)
email_address = response.supervisor_id
attachment "application/pdf" do |a|
    a.body = Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000) #timeout here
    a.filename = "test.pdf" 
end
mail to: email_address, subject: 'Thank you for your feedback!'

end

如果我切换 a.body 和 a.filename,它首先会出错

undefined method `filename=' for #<Mail::Part:0x007ff620e05678>

我发现的每个示例都有不同的语法或建议但没有解决 Net::HTTP 超时的问题。 Rails 3.1、Ruby 1.9.2

I am using Prawn to generate a PDF from my controller, and when accessed directly at the url, it works flawlessly, I.E. localhost:3000/responses/1.pdf

However, when I try to generate this file on the fly for inclusion in a Mailer, everything freezes up and it times out.

I have tried various methods for generating / attaching the file and none have changed the outcome.

I also tried modifying the timeout for Net::HTTP to no avail, it just takes LONGER to time out.

If I run this command on the Rails Console, I receive a PDF data stream.

Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000)

But if I include this code in my controller, it times out.

I have tried two different methods, and both fail repeatedly.

Method 1
Controller:

http = Net::HTTP.new('localhost', 3000)
http.read_timeout = 6000
file = http.get(response_path(@response, :format => 'pdf')) #timeout here
ResponseMailer.confirmComplete(@response,file).deliver #deliver the mail!

Method 1 Mailer:

def confirmComplete(response,file)
  email_address = response.supervisor_id
  attachments["test.pdf"] = {:mime_type => "application/pdf", :content=> file}
  mail to: email_address, subject: 'Thank you for your feedback!'
end

The above code times out.

Method 2 Controller:

ResponseMailer.confirmComplete(@response).deliver #deliver the mail!

Method 2 Mailer:

def confirmComplete(response)
email_address = response.supervisor_id
attachment "application/pdf" do |a|
    a.body = Net::HTTP.get('127.0.0.1',"/responses/1.pdf", 3000) #timeout here
    a.filename = "test.pdf" 
end
mail to: email_address, subject: 'Thank you for your feedback!'

end

If I switch the a.body and a.filename, it errors out first with

undefined method `filename=' for #<Mail::Part:0x007ff620e05678>

Every example I find has a different syntax or suggestion but none fix the problem that Net::HTTP times out. Rails 3.1, Ruby 1.9.2

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

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

发布评论

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

评论(2

人心善变 2024-12-28 06:26:26

问题是,在开发过程中,您只运行一个服务器进程,该进程正忙于生成电子邮件。该进程正在向其自身发送另一个生成 PDF 的请求并等待响应。对 PDF 的请求基本上是在服务器上排队以便获取 PDF,但服务器正忙于生成电子邮件并等待在完成之前获取 PDF。因此,你将永远等待。

您需要做的是启动第二个服务器进程...

script/rails server -p 3001

然后使用类似的内容获取您的PDF...

args = ['127.0.0.1','/responses/1.pdf']
args << 3001 unless Rails.env == 'production'
file = Net::HTTP.get(*args)

顺便说一句,根据您的生产计算机上运行的服务器,您可能会遇到指向问题位于 127.0.0.1。您可能需要在生产时使其动态化并指向完整的域,但这应该很容易。

The problem is that, in development, you're only running one server process, which is busy generating the email. That process is sending another request (to itself) to generate a PDF and waiting for a response. The request for the PDF is basically standing in line at the server so that it can get it's PDF, but the server is busy generating the email and waiting to get the PDF before it can finish. And thus, you're waiting forever.

What you need to do is start up a second server process...

script/rails server -p 3001

and then get your PDF with something like ...

args = ['127.0.0.1','/responses/1.pdf']
args << 3001 unless Rails.env == 'production'
file = Net::HTTP.get(*args)

As an aside, depending on what server you're running on your production machine, you might run into issues with pointing at 127.0.0.1. You might need to make that dynamic and point to the full domain when in production, but that should be easy.

栖竹 2024-12-28 06:26:26

我同意 https://stackoverflow.com/users/811172/jon-garvin 的分析,您'仅运行一个服务器进程,但我会提到另一种解决方案。重构您的 PDF 生成,这样您就不再依赖您的控制器。

如果您使用 Prawnto,我猜您有类似的视图

# app/views/response.pdf.prawn
pdf.text "Hello world"

将其移至您的 Response 模型:(或者其他更合适的地方,例如演示者)

# app/models/response.rb
require 'tmpdir'
class Response < ActiveRecord::Base
  def pdf_path
    return @pdf_path if @pdf_generated == true
    @pdf_path = File.join(Dir.tmpdir, rand(1e11).to_s)
    Prawn::Document.generate(@pdf_path) do |pdf|
      pdf.text "Hello world"
    end
    @pdf_generated = true
    @pdf_path
  end

  def pdf_cleanup
    if @pdf_generated and File.exist?(@pdf_path.to_s)
      File.unlink @pdf_path
    end
  end
end

然后在您的 ResponsesController 中您可以执行以下操作:

# app/controllers/responses_controller.rb
def show
  @response = Response.find params[:id]
  respond_to do |format|
    # this sends the PDF to the browser (doesn't email it)
    format.pdf { send_file @response.pdf_path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'test.pdf' }
  end
end

在您的邮件程序中您可以执行以下操作:

# this sends an email with the PDF attached
def confirm_complete(response)
  email_address = response.supervisor_id
  attachments['test.pdf'] = {:mime_type => "application/pdf", :content => File.read(response.pdf_path, :binmode => true) }
  mail to: email_address, subject: 'Thank you for your feedback!'
end

由于您在 tmpdir 中创建了它,因此它将自动地服务器重新启动时删除。您还可以调用清理函数。

最后一点:您可能想使用不同的模型名称,例如 SupervisorReport 或其他名称 - Response 可能会在稍后给您带来命名空间问题)

I agree with https://stackoverflow.com/users/811172/jon-garvin's analysis that you're only running one server process, but I would mention another solution. Refactor your PDF generation so you don't depend on your controller.

If you're using Prawnto, I'm guessing you have a view like

# app/views/response.pdf.prawn
pdf.text "Hello world"

Move this to your Response model: (or somewhere else more appropriate, like a presenter)

# app/models/response.rb
require 'tmpdir'
class Response < ActiveRecord::Base
  def pdf_path
    return @pdf_path if @pdf_generated == true
    @pdf_path = File.join(Dir.tmpdir, rand(1e11).to_s)
    Prawn::Document.generate(@pdf_path) do |pdf|
      pdf.text "Hello world"
    end
    @pdf_generated = true
    @pdf_path
  end

  def pdf_cleanup
    if @pdf_generated and File.exist?(@pdf_path.to_s)
      File.unlink @pdf_path
    end
  end
end

Then in your ResponsesController you can do:

# app/controllers/responses_controller.rb
def show
  @response = Response.find params[:id]
  respond_to do |format|
    # this sends the PDF to the browser (doesn't email it)
    format.pdf { send_file @response.pdf_path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'test.pdf' }
  end
end

And in your mailer you can do:

# this sends an email with the PDF attached
def confirm_complete(response)
  email_address = response.supervisor_id
  attachments['test.pdf'] = {:mime_type => "application/pdf", :content => File.read(response.pdf_path, :binmode => true) }
  mail to: email_address, subject: 'Thank you for your feedback!'
end

Since you created it in the tmpdir, it will be automatically deleted when your server restarts. You can also call the cleanup function.

One final note: you might want to use a different model name like SupervisorReport or something - Response might get you in namespacing trouble later)

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