使用wkhtmltopdf时ActionCable出现WebSocket握手错误求助
嘿,我之前也碰到过类似的情况,wkhtmltopdf对WebSocket的支持确实有点“挑剔”,结合你的场景,咱们一步步来排查解决:
1. 先排查wkhtmltopdf版本问题
旧版本的wkhtmltopdf(比如0.12.5及以下)对WebSocket协议的支持很不完善,容易出现握手失败。建议你升级到0.12.6或更高版本,这个版本开始对WebSocket的兼容性有明显提升。你可以通过wkhtmltopdf --version命令查看当前版本,然后替换为最新版即可。
2. 确保ActionCable允许wkhtmltopdf的请求来源
ActionCable默认会校验请求的Origin头,如果wkhtmltopdf发起请求时的Origin不在允许列表里,就会直接拒绝握手。你需要在Rails对应环境的配置文件里添加对应的Origin:
# config/environments/production.rb(或开发环境的config/environments/development.rb) Rails.application.config.action_cable.allowed_request_origins = [ 'https://your-production-domain.com', 'http://localhost:3000' # 本地开发环境添加 ]
如果不确定wkhtmltopdf发送的Origin是什么,可以去服务器日志里找WebSocket请求的Origin字段,把它加入允许列表就行。
3. 让PDF页面跳过ActionCable初始化
其实生成PDF的页面根本不需要实时WebSocket连接(毕竟PDF是静态文件),所以最直接的方法是在渲染PDF时,不加载ActionCable的相关代码。你可以在布局文件里加个判断:
# app/views/layouts/application.html.erb <% unless request.format.pdf? %> <%= action_cable_meta_tag %> <script src="/cable.js"></script> <!-- 其他ActionCable相关的JS代码也放在这里面 --> <% end %>
这样wkhtmltopdf渲染PDF页面时,就不会尝试建立WebSocket连接,自然也就不会出现握手错误了。
4. 给wkhtmltopdf添加WebSocket启用参数
如果你的业务场景确实需要在PDF页面里用到WebSocket(虽然这种情况不多见),可以尝试给wkhtmltopdf添加--enable-web-sockets命令行参数。如果你用的是wicked_pdf gem,配置如下:
# config/initializers/wicked_pdf.rb WickedPdf.config = { exe_path: '/usr/local/bin/wkhtmltopdf', # 替换成你的wkhtmltopdf实际路径 extra_args: ['--enable-web-sockets'] }
注意:这个参数不是所有版本都支持,建议先确认你的wkhtmltopdf版本是否支持该参数。
5. 替代方案:拆分进度展示与PDF生成
如果以上方法都不生效,建议调整流程:在用户的浏览器页面用ActionCable展示生成进度,当PDF生成完成后,再通知用户下载PDF文件。这样wkhtmltopdf只需要处理静态的PDF内容,完全不需要接触WebSocket,从根源上避免了握手问题。
内容的提问来源于stack exchange,提问作者Cristiano Mendonça

