【问题标题】:XMLHttpRequest.send() throws exception when asked for a DOM objectXMLHttpRequest.send() 在请求 DOM 对象时抛出异常
【发布时间】:2012-07-18 08:38:37
【问题描述】:

我想在 Firefox/Greasemonkey 用户脚本中以 document 检索 HTML 页面。

编辑:不是跨域请求。

这是我的示例代码:

var r = new XMLHttpRequest();
r.open("GET", document.location.href, true);
r.responseType = "document";
r.send(null);

这看起来就像 https://developer.mozilla.org/en/HTML_in_XMLHttpRequest 中的示例, 但是r.send(null) 会导致TypeError。原因,而不是抛出!在try...catch 中换行不会改变任何东西,似乎回调或事件处理程序引发了异常:

TypeError: document.location is null

回溯指的是 Firefox 内部的 event.js 文件,但不是我的脚本。

删除设置responseType 的行会消除异常,添加回调则不会。 但是,响应是有效的,responseXML 提供了一个 DOM 树。 我正在使用 FF 13.0.1。

是我遗漏了什么还是这是一个错误?

解决方案:这与 Mozilla 的 Addon Builder 创建的扩展有关,而不是 Firefox。

【问题讨论】:

  • 我在 Chrome 上收到以下错误:XMLHttpRequest cannot load https://www.google.de/. Origin http://fiddle.jshell.net is not allowed by Access-Control-Allow-Origin. 似乎很清楚...example here
  • 这是一个完全不同的问题。当然,当脚本源自jshell.net 时,不允许对google.com 发出http 请求。将其作为用户脚本尝试,此错误将消失。
  • Firefox 中没有 event.js 文件。听起来您安装了一些扩展程序,可以查看所有 XHR 并以某种方式搞砸了.... 有问题的 event.js 文件的完整 URI 是什么?
  • 你是对的。它不是 Firefox,而是使用 Mozilla 的 Addon Builder 创建的“Hello World”扩展。

标签: javascript firefox xmlhttprequest greasemonkey


【解决方案1】:

脚本正在google.com 上运行,而您正在尝试获取google.de,对吗?这是一个跨域请求。(另外,问题代码不是XMLHttpRequest 的有效同步或异步使用。)

要在 Greasemonkey 脚本(或 Chrome)中执行跨域(或不执行)AJAX,请使用 GM_xmlhttpRequest()
请注意,GM_xmlhttpRequest() 目前不允许您指定 responseType,但无论如何在这种情况下您都不需要这样做。如果你想要一个好的解析文档,请使用DOMParser

把它们放在一起:

GM_xmlhttpRequest ( {
    method:     'GET',
    //url:        'https://www.google.de/',
    url:        location.href,  // self get, checking for updates
    onload:     function (respDetails) {
                    processResponse (respDetails);
                }
} );

function processResponse (respDetails) {
    // DO ALL RESPONSE PROCESSING HERE...
    var parser  = new DOMParser ();
    var doc     = parser.parseFromString (respDetails.responseText, "text/html");

    //--- Example showing that the doc is fully parsed/functional...
    console.log (doc.querySelectorAll ("p") );
}




PS:因为这毕竟不是跨域的,所以原代码,更正应该是:

var r           = new XMLHttpRequest();

r.onload        = function () {
    // DO ALL RESPONSE PROCESSING HERE...
    console.log (this.response.querySelectorAll ("div") );
}
r.open ("GET", location.href, true);
r.responseType  = "document";
r.send (null);

用于异步请求。

【讨论】:

  • 我真的把那个示例代码搞砸了,对不起。这不是跨域请求,我调整了原帖。
  • 那请求document.location.href有什么意义呢?这是当前页面,您已经拥有它!此外,此答案的代码将无论如何都可以使用。
  • 检查页面的更新并将它们添加到当前视图而不刷新整个浏览器窗口。我可以在GM_xmlhttpRequest 中指定responseType 吗?
  • 不,您不能设置responseType,但在这种情况下,您也不需要设置。查看更新的答案。
  • 除了不忽略响应外,我看不出我的原始代码和您的更正之间的区别。无论如何,事实证明这个问题既不是 Ajax 也不是 Greasemonkey 相关的;感谢您对DOMParser 的提示。
【解决方案2】:

很遗憾,您不能从一个域到另一个域执行 Ajax:

http://en.wikipedia.org/wiki/Same_origin_policy

你可以读入CORS:

http://en.wikipedia.org/wiki/Cross-origin_resource_sharing

或 JSONP 作为可能的解决方案:

http://en.wikipedia.org/wiki/JSONP

但是,浏览器的设计方式使得人们不能随意跨域创建 Ajax 请求,因为这是一个安全问题。

如果您绝对需要从不同的域中获取内容,我会考虑使用cURL 创建您自己的服务器 API,在同一个域中提供您自己的内容,然后在那里使用 Ajax。否则,您必须查看 Google 是否会授予 CORS 访问权限或是否有某种内置的 JSONP 请求。

【讨论】:

  • 对于误导性的示例代码,我深表歉意。事实上,我是从脚本的域中请求的。它被设置为google.com 的用户脚本。请求甚至成功,但在进行中抛出异常。
  • @trion Weird... 我可以发誓位置对象是“window.location”而不是 document.location。试试用 window.location 吧?
  • 他们都做同样的事情。此外,传递给open() 的 URL 无关紧要,无论我在哪个站点上测试,都会出现完全相同的错误。
  • @trion 我正在查看我编写的一些旧代码,我省略了 responseType 行,也没有在 send() 方法中包含 null。
  • 是的,responseType 行似乎肯定是这里的问题。但是,如果我省略它,请求的响应类型是纯文本,但我需要一个 DOM 树来从中提取 HTML 元素。
猜你喜欢
  • 2021-09-03
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
  • 2016-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
相关资源
最近更新 更多