Chrome扩展程序中的Access-Control-Allow-Origin错误

时间:2012-02-04 19:53:56

标签: google-chrome google-chrome-extension same-origin-policy

我有一个chrome扩展程序,它以特殊方式监视浏览器,将一些数据发送到Web服务器。在当前配置中,这是localhost。所以内容脚本包含这样的代码:

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(data)...
xhr.open('GET', url, true);
xhr.send();

其中url参数为'http:// localhost / ctrl?params'(或http://127.0.0.1/ctrl?params - 无关紧要。)

Manifest-file包含跨站点请求的所有必要权限。

扩展程序在大多数网站上运行良好,但在一个网站上我收到错误:

XMLHttpRequest cannot load http://localhost/ctrl?params. Origin http://www.thissite.com is not allowed by Access-Control-Allow-Origin.

我已尝试过多次在此处提出的权限(*://*/*http://*/*<all_urls>),但没有人帮助解决问题。

所以,问题是这个特定网站可能出现什么问题(显然可能有其他网站有类似的不当行为,我想知道这个的性质),以及如何解决错误?

2 个答案:

答案 0 :(得分:10)

(tl; dr:在答案的最后看到两个可能的解决方法)

这是发生的一系列事件,这会导致您看到的行为:

  1. http://www.wix.com/开始加载
  2. 它有一个<script>标记,异步加载Facebook Connect脚本:
    (function() {
      var e = document.createElement('script');
      e.type = 'text/javascript';
      e.src = document.location.protocol +
        '//connect.facebook.net/en_US/all.js';
      e.async = true;
      document.getElementById('fb-root').appendChild(e);
    }());
    
  3. 加载wix.com页面的HTML(但不是资源,包括Facebook Connect脚本)后,DOMContentLoaded事件将触发。由于您的内容脚本使用"run_at" : "document_end",因此会在此时注入并运行。
  4. 您的内容脚本运行以下代码(据我所知,它希望在load事件触发后执行大部分工作):
    window.onload = function() {
      // code that eventually does the cross-origin XMLHttpRequest
    };
    
  5. Facebook Connect脚本加载,它有自己的load事件处理程序,它在此片段中添加:
    (function() {
      var oldonload=window.onload;
      window.onload=function(){
        // Run new onload code
        if(oldonload) {
          if(typeof oldonload=='string') {
            eval(oldonload);
          } else {
            oldonload();
          }
        }
      };
    })();
    
    (这是第一个关键部分)由于您的脚本设置了onload属性,oldonload是您脚本的加载处理程序。
  6. 最终,所有资源都已加载,load事件处理程序将触发。
  7. 运行Facebook Connect的load处理程序,运行自己的代码,然后调用oldonload。 (这是第二个关键部分)由于页面正在调用您的load处理程序,因此它不是在脚本的isolated world中运行,而是在页面的“主界”中运行。只有脚本的隔离世界具有跨源XMLHttpRequest访问权限,因此请求失败。
  8. 要查看简化的测试用例,请参阅this page(模仿http://www.wix.com),其中加载this script(模仿Facebook Connect)。我还提出了content scriptextension manifest的简化版本。

    您的load处理程序最终在“主要世界”中运行的事实很可能是Chrome bug 87520的一种表现形式(该错误具有安全隐患,因此您可能无法看到它)

    有两种方法可以解决这个问题:

    1. 您可以在文档加载后使用默认运行时间("run_at" : "document_end"),而不是使用loaddocument_idle事件处理程序,只需让代码以内联方式运行。
    2. 不是通过设置load属性添加window.onload事件处理程序,而是使用window.addEventListener('load', func)。这样,您的事件处理程序将不会对Facebook Connect可见,因此它将在内容脚本的孤立世界中运行。

答案 1 :(得分:1)

您看到的访问控制来源问题可能会显示在响应的标头中(超出您的控制范围),而不是请求(在您的控制范围内)。

Access-Control-Allow-Origin是CORS的策略,在标头中设置。例如,使用PHP,您可以使用一组标题来启用CORS:

header('Access-Control-Allow-Origin: http://blah.com');
header('Access-Control-Allow-Credentials: true' );
header('Access-Control-Allow-Headers: Content-Type, Content-Disposition, attachment');

如果服务器在此标头中设置了特定的来源,那么如果听起来像那样,那么您的Chrome extension遵循该指令以仅允许来自该域的跨域(POST?)请求。