Javascript 使用后台页面的跨域 XMLHttpRequest

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7699615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 03:13:58  来源:igfitidea点击:

Cross-domain XMLHttpRequest using background pages

javascriptgoogle-chromegoogle-chrome-extensionxmlhttprequestcross-domain

提问by yuzeh

In my Chrome extension, I want to have my options.htmlpage communicate with something like Google's OpenId API. In order to do this seamlessly, I have a hidden iframeon the options page which will pop-up the Google Accounts login page (following the OpenId interaction sequence, etc.).

在我的 Chrome 扩展程序中,我想让我的options.html页面与 Google 的 OpenId API 之类的东西进行通信。为了无缝地做到这一点,我iframe在选项页面上有一个隐藏,它将弹出 Google 帐户登录页面(遵循 OpenId 交互序列等)。

My issue is that I can't communicate from the options page to the iframe(the origin of the iframeis something I control, but not the same as my chrome extension) via window.postMessage. I was wondering if there is a quick workaround to this issue.

我的问题是,我无法从选项页传达给iframe(的起源iframe经是我控制,但由于我的Chrome扩展不一样的)window.postMessage。我想知道是否有解决此问题的快速解决方法。

If there isn't, I'm going to make options.htmlcontain an iframethat houses the layout and logic of the page.

如果没有,我将创建options.html一个包含iframe页面布局和逻辑的内容。

回答by Rob W

You don't have to mess with iframes. It's possible to perform cross-domain XMLHttpRequests, using background pages. Since Chrome 13, cross-site requests can be made from the content script. However, requests can still fail if the page is served with a Content Security Policy header with a restricting connect-src.

您不必弄乱 iframe。可以使用后台页面执行跨域 XMLHttpRequests。从 Chrome 13 开始,可以从内容脚本发出跨站点请求。但是,如果页面使用带有限制connect-src.

Another reason for choosing the nexy method over content scripts is that requests to http sites will cause a mixed content warning ("The page at https://... displayed insecure content from http://...").

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

Yet another reason for delegating the request to the background page is when you want to get a resource from the file://, because a content script cannot read from file:, unless it is running on a page at the file://scheme.

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

Note
To enable cross-origin requests, you have to explicitly grant permissions to your extension using the permissionsarray in your manifest file.

注意
要启用跨域请求,您必须使用permissions清单文件中的数组明确授予扩展程序权限。

Cross-site request using background script.

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

The content script would request the functionality from the background via the messagingAPI. Here is an example of a very simple way of sending and getting the response of a request.

内容脚本将通过消息传递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/ eventpage:

背景/活动页面:

/**
 * 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
    }
});

Remark: The messaging APIs have been renamed several times. If your target browser is not the latest Chrome version, check out this answer.

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

For completeness, here's a manifestfile to try out my demo:

为了完整起见,这里有一个清单文件来试用我的演示:

{
    "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
    }
}

回答by kishoreballa

I implemented the same thing using jquery its much simpler and it worked great too..

我使用 jquery 实现了同样的事情,它更简单,而且效果很好。

background.js

背景.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

内容脚本.js

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

But make sure manifest.json file has required permissions and jquery js file

但请确保 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" ]
  }