使用来自 phantom.js 的 jQuery 发送跨域 ajax 请求

Send a cross-domain ajax request using jQuery from phantom.js

我正在尝试通过模拟它在 phantomjs 上执行的部分操作来测试 chrome 插件。

我想让 phantom 做的事情看起来非常简单,但我遇到了问题。我希望它访问某个网页,并在此页面的上下文中 运行 一个脚本,该脚本将向我的后端发送 ajax 请求并打印出响应。为了让我的生活更轻松,我希望 phantom 使用 jQuery 发送 ajax 请求。

这是我传递给 phantom 的脚本 test1.js

var page = new WebPage(),
    url = 'http://www.example.com',

// Callback is executed each time a page is loaded...
page.open(url, function (status) {
  if (status === 'success') {
    console.log('opened url');
    start();
  }
});

function start(){
  page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() {
    console.log("got here");
    $.get("http://my-wonderful-site.com")
      .done(function( data ) {
        console.log("here!");
        console.log(data);
        phantom.exit(); 
      });
  });
}

命令phantomjs test1.js --web-security=false的控制台输出是:

opened url
got here
ReferenceError: Can't find variable: $

  test1.js:20
  :/modules/webpage.js:337

所以好像连jQuery都加载不出来,但是我也想不通我做错了什么。尝试 page.injectJs 从我的硬盘注入 jQuery,但得到了同样的错误。你能帮忙吗?

已编辑:

按照建议更新了函数:

function start(){
  page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() {
    console.log("got here");
    page.evaluate(function() {
      console.log("and here");
      $.get("http://my-wonderful-site.com")
        .done(function( data ) {
          console.log("here!");
          console.log(data);
          phantom.exit(); 
        });
    });
  });
}

现在phantom就挂了,控制台输出为:

phantomjs test1.js --web-security=false
opened url
got here

也就是说,$.get 之前的 console.log 甚至没有执行。

我很确定您需要在 page.evaluate 中才能实际使用注入的 JS(参见此处示例 http://phantomjs.org/page-automation.html)。尝试:

function start() {
    page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() {
        console.log("got here");
        page.evaluate(function() {
            $.get("http://my-wonderful-site.com")
            .done(function( data ) {
              console.log("here!");
              console.log(data);
              phantom.exit(); 
            });
        });
    });
}

PhantomJS 有两个上下文。内部上下文或页面上下文由 page.evaluate() 定义。它是沙盒的,无法访问外部定义的变量。所以,它不知道 phantom 是什么。同样,外部上下文不知道 $ 是什么,因为 jQuery 是一个 DOM 库并被注入到页面中。您需要将 jQuery 请求包装在 page.evaluate().

另一件事是现在,phantom.exit() 没有任何意义。您需要告诉 PhantomJS 从页面上下文内部退出,因为请求是异步的。这就是 page.onCallback and window.callPhantom() 对的用武之地。

page.onCallback = function(data){
  if (data.type === "exit") {
    phantom.exit();
  }
};

function start(){
  page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js', function() {
    console.log("got here");
    page.evaluate(function(){
      $.get("http://my-wonderful-site.com")
        .done(function( data ) {
          console.log("here!");
          console.log(data);
          window.callPhantom({type: "exit"});
        });
    });
  });
}

console.log() 是在页面上下文中定义的,但你在那里看不到它,因为 PhantomJS 默认情况下不会将它们传递出去。您必须注册 page.onConsoleMessage 活动。

您还可以在 callPhantom() 的帮助下将数据发送到外部上下文,而不是记录它。请注意,并非所有内容都可以在 contexts:

之间传递

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

Closures, functions, DOM nodes, etc. will not work!

其他有用的事件处理程序是 onError, onResourceError, onResourceTimeout,以防仍有问题。