为什么当Rails应用程序被终止时,PDFKit/wkhtmltopdf会挂起但仍能正常呈现PDF?

37

背景

经过阅读,我发现 Prawn 已经过时了,wkhtmltopdf 更为流行。同时,对于 Rails 来说,PDFKitwicked_pdf 也变得十分热门。我在 Ryan如何使用PDFKit 的视频中找到了一些有用的信息。我安装了所有必要的组件,并在 CLI 上测试了 wkhtmltopdf,没有出现任何问题。我还调整了 Rails 的设置,以便运行多个进程,使资产管道正常工作。看起来一切都很顺利,但是我仍然卡在了最后一个步骤上(从服务器获取 PDF 响应)。

问题

当我请求查看的 .pdf 版本(我正在使用 PDFKit 中间件选项)时,我的浏览器只是等待响应,但是当我杀死 Rails 进程时,我期望得到的 PDF 才会在浏览器窗口中弹出。这是怎么回事?

我使用了什么

  • 操作系统:OSX 10.8.1
  • Rails:3.2.8
  • Ruby:1.9.3
  • wkhtmltopdf:0.11.0_rc1(但是当我运行wkhtmltopdf -V时,它显示为0.10.0_rc2)
  • qt:4.8.2

我做了什么

  • 通过在application.rb文件中加载config.middleware.use "PDFKit::Middleware",我使用了PDFKit中间件。
  • 在我的Gemfile中包含gem 'pdfkit'并使用Bundler安装它。
  • 使用Mime::Type.register_alias "application/pdf", :pdf在我的mime_types.rb初始化程序中设置了.pdf MIME类型的别名。
  • config.threadsafe!添加到config/environments/development.rb中以支持多个线程,以避免资产管道与PDF引擎冲突。
  • 测试了wkhtmltopdf http://www.google.com google.pdf,并生成了预期的Google首页的PDF。
  • 尝试将PDFKit替换为wicked_pdf并遇到相同的问题(挂起,但当终止Rails进程后,PDF会如预期地呈现)。

外观效果

这是由Rails渲染的常规HTML页面(我已经模糊了客户端详细信息): enter image description here

这是我在尝试导航到localhost:3000/some/path.pdf时,Rails的CLI输出结果(应用程序在等待响应时挂起): enter image description here 当我最终使用ctrl-c杀死Rails进程后,PDF最终会像我期望看到的那样显示在浏览器中(CSS和HTML正常呈现,因此资产似乎加载良好): enter image description here 目前为止的结论: 将PDFKit换成wicked_pdf并获得相同的结果使我认为问题不在于这些库,而是与我的开发环境有关。但是,在命令行下运行wkhtmltopdf很好,所以这使我认为它和QT都在正常工作。问题必须在Rails中。也许我没有正确配置某些内容?
请求帮助: 我如何确定问题的具体内容以及如何解决它?
如果您能帮助我,我会非常感激 <3
更新
我也尝试了另一种渲染PDF的方法(使用.to_pdf),而不是使用中间件选项,具体操作如下:我注释掉了application.rb文件中的config.middleware.use "PDFKit::Middleware"
respond_to do |format|
    format.html
    format.pdf do
        html = '<html><body>This is a test.</body></html>'
        @pdf = PDFKit.new(html)

        send_data @pdf.to_pdf, 
            :filename => 'whatever.pdf', 
            :type => 'application/pdf', 
            :disposition => 'attachment'
    end
end

我想知道这是否与OSX 10.8有关?我正在等待客户设置生产服务器,以便再次测试。也许使用多线程服务器+不同的*nix环境的组合会有所帮助。无论如何,这对我的开发没有帮助。 - robmclarty
7个回答

70

问题出在wkhtmltopdf本身上,具体来说,是在0.9.9版本之后的所有版本。直接从命令行运行wkhtmltopdf时会卡住。

纠正步骤:

brew uninstall wkhtmltopdf
cd /usr/local/Library/Formula/
git checkout 6e2d550 /usr/local/Library/Formula/wkhtmltopdf.rb
brew install wkhtmltopdf

然后验证已安装正确版本wkhtmltopdf --version,应该得到wkhtmltopdf 0.9.9

引用:

  1. https://github.com/mileszs/wicked_pdf/issues/110
  2. http://wearepandr.com/blog/article/homebrew-and-installing-old-package-versions#blog_nav

6
一条命令完成2-4步骤:brew install https://raw.github.com/mxcl/homebrew/6e2d550cf4961129a790bfb0973f8e88704f439d/Library/Formula/wkhtmltopdf.rb - mfilej
3
如果您已经安装了Ruby,则可以跳过所有Homebrew的操作,直接使用gem install wkhtmltopdf来安装。删除现有的Homebrew符号链接:rm /usr/local/bin/wkhtmltopdf。然后链接到gem二进制文件,例如ln -s ~/.rvm/gems/ruby-2.0.0-p0/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf。使用which wkhtmltopdf命令查找这个二进制文件。在Gemfile中添加 gem 'wkhtmltopdf'。如果使用wicked_pdf gem,则将其配置设置为WickedPdf.config={exe_path: '/usr/local/bin/wkhtmltopdf'}。参考文献: wkhtmltopdf gem(0.1.2)安装了wkhtmltopdf二进制版本0.8.3 patched qt。 - scarver2
4
Gemfile中的gem 'wkhtmltopdf-binary'目前安装的是0.9.9版本,适用于那些想使用gem而不是brew的人。 - genkilabs
1
我曾尝试使用0.11.x版本,但是在折磨了自己很久(包括胸毛)之后,我找到了这个答案,像孩子一样哭泣。我的朋友,你救了我。 - Clifton Labrum
2
@Marklar wkhtmltopdf_binary gem实际上绕过了任何Homebrew安装,并使用在gem的bin文件夹中找到的版本。作者Dmitry Rocha一直在保持二进制文件的最新状态。 - scarver2
显示剩余8条评论

9

请尝试最新版本。在MacOS上安装的简单方法:

brew install Caskroom/cask/wkhtmltopdf

1
Wena abel, gracias! xD! - claudevandort

2

scarver2提供的解决方法对我很有用。但是我需要一个更新版本的wkhtmltopdf。由于homebrew版本似乎仍然过时(在命令行中仍然挂起),并且没有最新的预编译二进制文件可用,因此我使用了os x构建脚本来自己编译一个:

$ git clone git@github.com:wkhtmltopdf/wkhtmltopdf.git
$ cd wkhtmltopdf
$ ./build_osx.sh     # i'm running 10.9.2
$ bin/wkhtmltopdf --version                                                                                  
Name:
  wkhtmltopdf 0.12.1-72a9f2066fe9ffd162dec007a4d9b6a5cd63b670
$ curl www.example.com | bin/wkhtmltopdf - test.pdf  # render pdf of example.com
$ open test.pdf   # to confirm pdf 

我正在使用 pdfkit 0.6.2Rails 3.2.17。我将二进制文件放在 /vendor 中,在 pdfkit 的初始化器中,使用 config.wkhtmltopdf 指向它。到目前为止,一切都很好。


1

我遇到了同样的问题。按照堆栈中的答案,在application.rb中添加'config.threadsafe!'后,问题得以解决。希望这可以帮到你。


是的,我在我的development.rb文件中实现了config.threadsafe!。我理解在使用默认的webrick时,wkhtmltopdf和asset pipeline之间可能会发生死锁,因为它只使用一个线程。在我这样做之前,我的应用程序之前什么都没有做,所以这确实有助于进一步推进事情。然而,在等待PDF文件时它仍然挂起(我猜测浏览器没有从服务器接收到它?) - robmclarty
直到我从“thin”切换回“Webrick”,它对我也没有起作用。 - mikebridge

0

出现了完全相同的症状,但目前使用的是WickedPdf。此时,我认为问题也在于wkhtmltopdf

不幸的是,我在Stack/Google上找到的建议都没有对我起作用。相反,我需要结合几个建议,包括在这篇文章中发现的一些建议。

解决方案如下:

  1. brew uninstall wkhtmltopdf
  2. /usr/bin 中查找并删除任何 wkhtmltopdf 的副本
  3. config/initializers 中注释掉 WickedPdf.config
  4. development.rb 中添加 config.threadsafe!
  5. 删除中间件并允许主控制器的 'show' 动作处理 pdf 请求(可能不必要)
  6. 在 gemfile 中添加 wkhtmltopdf-binary
  7. 运行 bundle
  8. 重启服务器
  9. 你可能还需要在 config/initializers/mime_types.rb 中添加 Mime::Type.register_alias "application/pdf", :pdf (对我来说,这会导致“警告:已初始化常量 PDF”)

我的设置是:Mac OSX Mountain Lion,Rails 3.2.1,Webrick,Postgres 和 wkhtmltopdf-binary (0.9.9.1)。


0

我的也卡住了,而且在dock中打开wkhtmltopdf图标也是如此。

实际上,我发现我的问题是只有一个独角兽工作进程在运行。一旦我添加了多个,它就正常工作了。

我正在OS X上运行wkhtmltopdf 0.9.9和pdfkit 0.6.2。


-2
尝试按照以下方式编辑config/initializer/pdfkit.rb文件:
PDFKit.configure do |config|

config.wkhtmltopdf = Rails.root.join('bin', 'wkhtmltopdf-i386').to_s

config.default_options = {

  :encoding=>"UTF-8",
  :page_size=>"A4",
  :margin_top=>"0.25in",
  :margin_right=>"0.1in",
  :margin_bottom=>"0.25in",
  :margin_left=>"0.1in",
  :disable_smart_shrinking=> false
}
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接