使用后台页面的跨域XMLHttpRequest

时间:2011-10-08 20:33:50

标签: javascript google-chrome google-chrome-extension xmlhttprequest cross-domain

在我的Chrome扩展程序中,我想让我的options.html页面与Google的OpenId API进行通信。为了无缝地执行此操作,我在选项页面上有一个隐藏的iframe,它会弹出Google帐户登录页面(按照OpenId交互顺序等)。

我的问题是我无法从选项页面与iframe进行通信(iframe的来源是我控制的,但与我的Chrome扩展程序不同)来自{{ 1}}。我想知道这个问题是否有快速的解决方法。

如果没有,我将使window.postMessage包含一个options.html,其中包含页面的布局和逻辑。

2 个答案:

答案 0 :(得分:37)

你不必搞乱iframe。可以使用后台页面执行跨域XMLHttpRequests。从Chrome 13开始,可以从内容脚本中进行跨站点请求。但是,如果页面是使用限制为connect-src的内容安全策略标头提供的,则请求仍然可能失败。

对内容脚本选择nexy方法的另一个原因是对http站点的请求将导致混合内容警告(“https://页面显示来自http:// ...的不安全内容”)

将请求委派给后台页面的另一个原因是,当您想要从file://获取资源时,因为内容脚本无法从file:读取,除非它在页面上运行在file://计划。

  

注意
  要启用跨源请求,您必须使用清单文件中的permissions数组向扩展显式授予权限。

使用后台脚本的跨站点请求。

内容脚本将通过messaging API从后台请求功能。以下是发送和获取请求响应的一种非常简单的方法示例。

chrome.runtime.sendMessage({
    method: 'POST',
    action: 'xhttp',
    url: 'http://www.stackoverflow.com/search',
    data: 'q=something'
}, function(responseText) {
    alert(responseText);
    /*Callback function to deal with the response*/
});

Background / event页面:

/**
 * Possible parameters for request:
 *  action: "xhttp" for a cross-origin HTTP request
 *  method: Default "GET"
 *  url   : required, but not validated
 *  data  : data to send in a POST request
 *
 * The callback function is called upon completion of the request */
chrome.runtime.onMessage.addListener(function(request, sender, callback) {
    if (request.action == "xhttp") {
        var xhttp = new XMLHttpRequest();
        var method = request.method ? request.method.toUpperCase() : 'GET';

        xhttp.onload = function() {
            callback(xhttp.responseText);
        };
        xhttp.onerror = function() {
            // Do whatever you want on error. Don't forget to invoke the
            // callback to clean up the communication port.
            callback();
        };
        xhttp.open(method, request.url, true);
        if (method == 'POST') {
            xhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        }
        xhttp.send(request.data);
        return true; // prevents the callback from being called too early on return
    }
});

备注:消息传递API已多次重命名。如果您的目标浏览器不是最新的Chrome版本,请查看this answer

为了完整性,这里有一个manifest文件来试用我的演示:

{
    "name": "X-domain test",
    "manifest_version": 2,
    "permissions": [
        "http://www.stackoverflow.com/search*"
    ],
    "content_scripts": {
        "js": ["contentscript.js"],
        "matches": ["http://www.example.com/*"]
    },
    "background": {
        "scripts": ["background.js"],
        "persistent": false
    }
}

答案 1 :(得分:4)

我使用jquery实现了同样的功能,它更简单,也很有效。

background.js

chrome.runtime.onMessage.addListener(function(request, sender, callback) {
  if (request.action == "xhttp") {

    $.ajax({
        type: request.method,
        url: request.url,
        data: request.data,
        success: function(responseText){
            callback(responseText);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            //if required, do some error handling
            callback();
        }
    });

    return true; // prevents the callback from being called too early on return
  }
});

contentscript.js

chrome.runtime.sendMessage({
        method: 'POST',
        action: 'xhttp',
        url: 'http://example-url.com/page.php',
        data: "key=value"
    }, function(reponseText) {
        alert(responseText);
    }); 

但请确保manifest.json文件具有所需权限和jquery js文件

  "permissions": [
      "tabs", "activeTab", "http://example-url.com/*"
  ],
  "content_scripts": [ {
      "js": [ "jquery-3.1.0.min.js", "contentscript.js" ],
      "matches": [ "https://example-ssl-site.com/*" ]
  }],
  "background": {
      "scripts": [ "jquery-3.1.0.min.js", "background.js" ]
  }