【问题标题】:PDFkit hangs when generating a pdf with an image生成带有图像的 pdf 时,PDFkit 挂起
【发布时间】:2013-12-21 01:25:53
【问题描述】:

我想将网页呈现为 PDF。它使用单个图像,我读到您需要为 PDFkit 提供绝对 URL 才能使用该图像,所以我的代码是:

= image_tag image_url(user.avatar)

这在以 HTML 格式查看时有效,并且 PDFkit 能够生成删除图像的 PDF。但是,在使用图像时,它会一直挂起,直到我终止服务器。我怎样才能让它工作?

这是我杀死服务器时的完整输出:

2013-12-04 13:53:36.576 wkhtmltopdf[27410:507] CoreText performance note: Client called CTFontCreateWithName() using name "Arial" and got font with PostScript name "ArialMT". For best performance, only use PostScript names when calling this API.
2013-12-04 13:53:36.577 wkhtmltopdf[27410:507] CoreText performance note: Set a breakpoint on CTFontLogSuboptimalRequest to debug.
2013-12-04 13:53:36.582 wkhtmltopdf[27410:507] CoreText performance note: Client called CTFontCreateWithName() using name "Arial" and got font with PostScript name "ArialMT". For best performance, only use PostScript names when calling this API.
2013-12-04 13:53:36.584 wkhtmltopdf[27410:507] CoreText performance note: Client called CTFontCreateWithName() using name "Arial" and got font with PostScript name "ArialMT". For best performance, only use PostScript names when calling this API.
^C
RuntimeError - command failed: /usr/local/bin/wkhtmltopdf --page-size Legal --print-media-type --quiet - -:
  pdfkit (0.5.4) lib/pdfkit/pdfkit.rb:73:in `to_pdf'
  pdfkit (0.5.4) lib/pdfkit/middleware.rb:21:in `call'
  warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
  warden (1.2.3) lib/warden/manager.rb:34:in `catch'
  warden (1.2.3) lib/warden/manager.rb:34:in `call'
  rack (1.5.2) lib/rack/etag.rb:23:in `call'
  rack (1.5.2) lib/rack/conditionalget.rb:25:in `call'
  rack (1.5.2) lib/rack/head.rb:11:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/flash.rb:241:in `call'
  rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/cookies.rb:486:in `call'
  activerecord (4.0.0) lib/active_record/query_cache.rb:36:in `call'
  activerecord (4.0.0) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
  activerecord (4.0.0) lib/active_record/migration.rb:369:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.0.0) lib/active_support/callbacks.rb:373:in `_run__4124003592524659480__call__callbacks'
  activesupport (4.0.0) lib/active_support/callbacks.rb:80:in `run_callbacks'
  actionpack (4.0.0) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/reloader.rb:64:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
  better_errors (1.0.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (1.0.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (1.0.1) lib/better_errors/middleware.rb:56:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.0.0) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.0.0) lib/rails/rack/logger.rb:21:in `block in call'
  activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `block in tagged'
  activesupport (4.0.0) lib/active_support/tagged_logging.rb:25:in `tagged'
  activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `tagged'
  railties (4.0.0) lib/rails/rack/logger.rb:21:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
  rack (1.5.2) lib/rack/runtime.rb:17:in `call'
  activesupport (4.0.0) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
  rack (1.5.2) lib/rack/lock.rb:17:in `call'
  actionpack (4.0.0) lib/action_dispatch/middleware/static.rb:64:in `call'
  railties (4.0.0) lib/rails/engine.rb:511:in `call'
  railties (4.0.0) lib/rails/application.rb:97:in `call'
  rack (1.5.2) lib/rack/content_length.rb:14:in `call'
  thin (1.6.0) lib/thin/connection.rb:82:in `block in pre_process'
  thin (1.6.0) lib/thin/connection.rb:80:in `catch'
  thin (1.6.0) lib/thin/connection.rb:80:in `pre_process'
  thin (1.6.0) lib/thin/connection.rb:55:in `process'
  thin (1.6.0) lib/thin/connection.rb:41:in `receive_data'
  eventmachine (1.0.3) lib/eventmachine.rb:187:in `run_machine'
  eventmachine (1.0.3) lib/eventmachine.rb:187:in `run'
  thin (1.6.0) lib/thin/backends/base.rb:73:in `start'
  thin (1.6.0) lib/thin/server.rb:162:in `start'
  rack (1.5.2) lib/rack/handler/thin.rb:16:in `run'
  rack (1.5.2) lib/rack/server.rb:264:in `start'
  railties (4.0.0) lib/rails/commands/server.rb:84:in `start'
  railties (4.0.0) lib/rails/commands.rb:78:in `block in <top (required)>'
  railties (4.0.0) lib/rails/commands.rb:73:in `tap'
  railties (4.0.0) lib/rails/commands.rb:73:in `<top (required)>'
  bin/rails:4:in `require'
  bin/rails:4:in `<main>'

【问题讨论】:

    标签: ruby-on-rails pdf ruby-on-rails-4 wkhtmltopdf pdfkit


    【解决方案1】:

    这是一个臭名昭著的问题,您遇到了这个问题,因为您的 HTML 中可能有相对链接的资产(即图像、CSS、JS、字体等),而您的 Web 服务器只能处理一个请求/线程一次(如WEBrick)。

    那么会发生什么?当您请求其 URL 时,服务器开始生成 PDF。 PDFkit 找到一个链接的资产,因此它尝试从服务器加载该资产,该服务器恰好是运行 PDFkit 的同一台服务器。但是,服务器的单线程已经忙于运行 PDFkit,因此它无法“腾出”来服务所请求的资产。总之,这是一个死锁——PDFkit 正在等待 PDFkit 完成处理的同一台服务器上的资产上等待,以便它可以将资产提供给 PDFkit...

    解决方案:或者Base64-embed your assets in the HTML,这样 PDFkit 就不需要发出任何额外的请求(我个人首选的解决方案),或者临时将资产卸载到另一台服务器(例如临时 AWS 存储桶) .您也可以尝试使用启用多线程的unicornThin 网络服务器,或者在in application.rb 中添加config.threadsafe!,但不能保证这些方法都有效。

    当然,这些技巧(嵌入资产或在其他地方托管)只能在开发环境中使用——您不应该在生产环境中遇到此类问题,因为实时服务器应该(希望)能够处理多个 GET 请求。

    【讨论】:

    • 我实际上改用 wicked_pdf 来让它工作,但我很欣赏对发生的事情的解释!
    • 有趣的是,切换后问题就解决了,因为wicked_pdf 在后台仍然使用wkhtmltopdf。旧版本的 wkhtmltopdf 不会导致赛车状况,所以可能就是这种情况。
    • 确实切换到独角兽有帮助!当我将我的应用程序从 Rails 3 升级到 Rails 4.2 时,我遇到了这个问题。但在我的情况下,我使用 wkhtmltopdf 0.9.9 还是 0.12.2 并不重要......每次我将带有图像的 html 模板渲染为 pdf 时,它都会失败。切换到 Rails 3.2 或 Rails 4 下的 unicorn 会有所帮助。我仍然想知道为什么它可以在 Rails 3.2 上运行?不同的WEBrick?
    【解决方案2】:

    您可以在开发中使用unicorn 一次服务多个请求。并且易于设置。 参考 http://dave.is/unicorn.htmlhttps://devcenter.heroku.com/articles/rails-unicorn

    它解决了我在开发中的问题。

    【讨论】:

      【解决方案3】:

      这是一个工作区助手

      Arman 的回答对我帮助很大。这是我想出的一个实现。

      module PdfHelper
      
        def pdf_image_tag(image_name)
          if Rails.env.development? || Rails.env.test?
            # Unless running a web server that can process 2 requests at the same
            # time, trying to insert an image in a PDF creates a deadlock: the server
            # can't finish processing the PDF request until it gets the image, but it
            # can't start processing the image request until it has finished
            # processing the PDF request.
            # This will not be a problem in production, but in dev, a workaround is
            # to base64 the image and insert its contents into the HTML
            image_data = Rails.application.assets[image_name].to_s
            image_tag "data:image/png;base64,#{::Base64.encode64(image_data)}"
          else
            image_tag image_name
          end
        end
      
      end
      

      【讨论】:

        【解决方案4】:

        您收到此错误是因为默认情况下 WEBrick 是一个单线程服务器,并且能够一次完成一个请求(因为单个工作线程)。要在 Rails 4.0 中获得完全多线程的 WEBrick,只需将此添加到config/initializers/multithreaded_webrick.rb

        # Remove Rack::Lock so WEBrick can be fully multi-threaded.
        require 'rails/commands/server'
        
        class Rails::Server
          def middleware
            middlewares = []
            middlewares << [Rails::Rack::Debugger] if options[:debugger]
            middlewares << [::Rack::ContentLength]
        
            Hash.new middlewares
          end
        end
        

        在您的 application.rb 中添加 config.middleware.delete 'Rack::Lock'

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多