【问题标题】:When rendering a page, can't load external resources渲染页面时,无法加载外部资源
【发布时间】:2014-05-15 10:29:04
【问题描述】:

我目前正在尝试通过 Node 和 PhantomJS 从 HTML 页面生成 PDF 文档。

如果我的页面包含本地资源,或者只有静态的东西,它可以正常工作:

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <link rel="StyleSheet" media="screen" href="./style.css" />
        <link rel="StyleSheet" media="print" href="./print.css" />
    </head>
    <body>
        <h1>The title</h1>
        <p>hai <span class="foo">lol <span class="bar">I'm generating</span> a pdf</span> !</p>
        <p class="centre"><img src="http://www.gratuit-en-ligne.com/telecharger-gratuit-en-ligne/telecharger-image-wallpaper-gratuit/image-wallpaper-animaux/img/images/image-wallpaper-animaux-autruche.jpg" /></p>
        <canvas id="test_canvas" width="200px" height="100px"/>

        <script>
            setTimeout(function () {
                var ctx = document.getElementById('test_canvas').getContext('2d');

                ctx.fillStyle = '#FF0000';
                ctx.fillRect(0, 0, 150, 75);
            }, 1000);

            setTimeout(function () {
                evt = document.createEvent('CustomEvent');
                evt.initEvent('pdfTrigger', true, false);

                document.dispatchEvent(evt);
            }, 3000);
        </script>
    </body>
</html>

所以在这里,图像被正确渲染,样式表也被正确渲染。但是,如果我从一个遥远的图像或一个遥远的脚本添加一个包含(以//http://https:// 开头的内容,即使它是针对我的本地环境的),内容也不会加载:

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <link rel="StyleSheet" media="screen" href="./style.css" />
        <link rel="StyleSheet" media="print" href="./print.css" />
    </head>
    <body>
        <h1>The title</h1>
        <p>hai <span class="foo">lol <span class="bar">I'm generating</span> a pdf</span> !</p>
        <p class="centre"><img src="http://upload.wikimedia.org/wikipedia/commons/7/7c/Ostrich,_mouth_open.jpg" /></p>

        <script>
            setTimeout(function () {
                evt = document.createEvent('CustomEvent');
                evt.initEvent('pdfTrigger', true, false);

                document.dispatchEvent(evt);
            }, 3000);
        </script>
    </body>
</html>

图像未渲染;如果我尝试使用来自 cdn 的 jQuery 包含和一些 jQuery 代码(例如通过$(document).trigger('pdfTrigger') 触发事件),它会显示ReferenceError: Can't find variable: $,因此该事件永远不会被触发。如果我将它包含在本地资源(如&lt;script src="./jquery.min.css"&gt;&lt;/script&gt;)的 html 文件中,错误就会消失,但永远不会触发事件...

这是我正在使用的 phantomjs 脚本:

/**
 * Render a PDF from an HTML file
 *
 * @author Baptiste Clavié <baptiste@wisembly.com>
 * Adapted from PhantomJs' example "rasterize.js"
 */

var orientation = 'portrait',
    system = require('system'),
    args = system.args.slice(1);

if (args.length < 2 || args.length > 3) {
    system.stderr.writeLine('Usage: rasterize.js source output [orientation]');
    system.stderr.writeLine('   source : html source to put in the pdf');
    system.stderr.writeLine('   output : output when the pdf will be written');
    system.stderr.writeLine('   orientation : document orientation (either portrait or landscape');

    phantom.exit((args.length === 1 & args[0] === '--help') ? 0 : 1);
}

if (typeof args[2] !== 'undefined') {
    if (-1 === ['portrait', 'landscape'].indexOf(args[2])) {
        system.stderr.writeLine('Invalid argument for [orientation]');
        system.stderr.write('Expected either "portrait", either "landscape" ; got "' + args[2] + '"');

        phantom.exit(1);
    }

    orientation = args[2];
}

var page = require('webpage').create(),
    identifier = '___RENDER____';

page.paperSize = { format: 'A4', orientation: orientation, margin: '1cm' };

page.onInitialized = function() {
    page.evaluate(function(identifier) {
        document.addEventListener('pdfTrigger', function () {
            console.log(identifier);
        }, false);
    }, identifier);
};

page.onError = function (msg, trace) {
    system.stderr.writeLine(msg);

    trace.forEach(function(item) {
        system.stderr.writeLine('   ' + item.file + ':' + item.line);
    });

    phantom.exit(1);
}

page.onConsoleMessage = function (msg) {
    console.log(msg);

    if (msg !== identifier) {
        return;
    }

    page.render(args[1], { format: 'pdf' });
    phantom.exit(0);
}

page.open(args[0], function (status) {
    if (status !== 'success') {
        system.stderr.write('Unable to load the file "' + args[0] + '"');
        phantom.exit(1);
    }
});

要启动我的脚本,我使用以下命令:phantomjs rasterize.pdf test.html test.pdf

总而言之,当我尝试在 Phantom 中渲染它时,似乎无法从 html 加载任何外部内容,并且无法识别 jQuery(可能还有其他一些脚本?)

有什么想法吗?如果需要更精确,请不要犹豫。

【问题讨论】:

    标签: node.js pdf-generation phantomjs


    【解决方案1】:

    变化:

    setTimeout(function () {
        evt = document.createEvent('CustomEvent');
        evt.initEvent('pdfTrigger', true, false);
    
        document.dispatchEvent(evt);
    }, 3000);
    

    收件人:

    window.onload = function () {
        evt = document.createEvent('CustomEvent');
        evt.initEvent('pdfTrigger', true, false);
    
        document.dispatchEvent(evt);
    };
    

    它失败的原因是因为该图像非常大,并且您在正确下载图像之前触发了 pdf 事件。使用window.onload 是可靠的,因为onload 事件只会在所有页面资源都加载完毕后运行。

    【讨论】:

    • 这可以解决加载外部资源的问题,但现在我遇到了另一个不相关的问题。请注意,setTimeout 的使用在这里只是为了模拟“在我的网页上做事”,因为您可以想象给定的 html 并不是我真正想要呈现的内容。不过谢谢。 :)
    • 那么就做window.onload = function() { setTimeout(function() { /* do stuff, then dispatch the pdf event */ }, 3000); };
    • 是的,这就是我继续处理下一个问题的想法。 :)
    猜你喜欢
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多