Javascript 如何在Webextension中使用正确的权限运行跨域XHR请求?

Javascript 如何在Webextension中使用正确的权限运行跨域XHR请求?,javascript,google-chrome-extension,xmlhttprequest,cross-domain,firefox-addon-webextensions,Javascript,Google Chrome Extension,Xmlhttprequest,Cross Domain,Firefox Addon Webextensions,目标:我想开发一个Firefox Web扩展(类似于Chrome扩展),在加载HTML和JavaScript文件之前检测它们。如果这些文件中有特定内容,它们将被阻止,否则它们将被允许通过 问题:无法收集具有不同域的文件内容,因为它们抛出“跨源”错误,因为缺少Access Control Allow Origin标头 我读了很多关于这个问题的资料,文档中说,如果在Webextension清单中设置了权限,就不需要Access Control Allow Origin头。以下引述: 使用权限键为您的

目标:我想开发一个Firefox Web扩展(类似于Chrome扩展),在加载HTML和JavaScript文件之前检测它们。如果这些文件中有特定内容,它们将被阻止,否则它们将被允许通过

问题:无法收集具有不同域的文件内容,因为它们抛出“跨源”错误,因为缺少Access Control Allow Origin标头

我读了很多关于这个问题的资料,文档中说,如果在Webextension清单中设置了权限,就不需要Access Control Allow Origin头。以下引述:

使用权限键为您的分机请求特殊权限。 […]密钥可以包含三种权限:[…]主机 权限[…]主机权限指定为匹配模式, 每个模式都标识一组URL,扩展是针对这些URL的 请求额外特权。额外的权限包括:XHR访问权限 到那些来源[…]

My manifest.json:

{
  [...],    
  "permissions": [
    "tabs",
    "*://*/*",
    "webRequest",
    "webRequestBlocking",
    "<all_urls>"
  ],    
  "background": {
    "scripts": ["backgroundscript.js"]
  },    
  "content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["/lib/jquery-2.2.4.min.js", "/contentscript.js"],
      "run_at": "document_start"
    }
  ]
}
在contentscript.js中,我使用jQuery$.get方法访问网站内容。我还尝试了使用数据类型jsonp$.ajax,但在这种情况下,我得到了一个无限访问链,脚本尝试无限次地加载resources。我一点也不明白,为什么会发生这种情况,可能是因为我使用了chrome.webRequest.onBeforeRequest侦听器,如果出现新连接,就会访问该侦听器,在这种情况下,它会进入无休止的循环

在我阅读的文章中,chrome.webRequest.onBeforeRequest有一个参数,requestBody:

包含HTTP请求正文数据。[...] 1. Firefox不支持“requestBody”选项

  • 此解决方案最好=>但不可用
  • 我尝试了$.get with permission pattern=>I get Cross-Origin错误
  • 我用jsonp和相同的权限模式尝试了$.ajax=>我得到了无尽的循环

  • 那么问题又来了:如果域名是开放的(模式类似“*:/*/*/*”),我如何访问不同域的文件内容而不出现跨源错误?

    最后,我可以在contentscript.js上用以下代码修复我的问题:

    chrome.webRequest.onBeforeRequest.addListener(
        logURL,
        {urls: ["<all_urls>"], types: ["main_frame", "script"]},
        ["blocking"]
    );
    
    function logURL(requestDetails) {
        chrome.tabs.sendMessage(
            requestDetails.tabId,
            {action: "getContentByURL", url: requestDetails.url, type: requestDetails.type},
            function(response) {
                console.log(response);
            }
        );
        if(requestDetails.type == 'script') {
            // here will be the conditions, based on the content of the files,
            // if they will be canceled or allowed to pass
            // actually, there is just a dummy "false"
            return {cancel: false};
        }
    }
    
    chrome.runtime.onMessage.addListener(
        function(message, sender, sendResponse) {
            var contentAll = [];
            if(message.action == 'getContentByURL') {
                var pageContent = getContentByURL(message.url);
                contentAll.push(pageContent);
                sendResponse({"content" : contentAll});
            }
        }
    );
    function getContentByURL(url) {
        $(document).ready(function() {
            $.get(url, function(data) {
                console.log(data);
            });
        });
    }
    
    chrome.runtime.onMessage.addListener(
        function(message, sender, sendResponse) {
            if(message.action == 'getContentByURL') {
                getContentByURL(message.url, function(result) {
                    sendResponse({"content" : result});
                });
            } else {
                sendResponse('error');
            }
            return true;
        }
    );
    
    function getContentByURL(url, callback) {
        var req = new XMLHttpRequest();
        if(req) {
            req.open('GET', url, true);
            req.onreadystatechange =  function() {
                if (req.readyState == 4) {
                    callback(req.responseText);
                }
            };
            req.send();
        }
    }
    
    一个重要的更改是使用XMLHttpRequest()对象而不是jQuery方法。这就是我的问题的解决方案。我以前试过这个,但是没有通过req.onreadystatechange的检查,所以我做错了。我用req.onload也试过了,这对我也适用

    要运行该示例,还有两个要点

    首先,我必须通过回调将内容(req.responseText)抛出,以便将响应从内容脚本发送回后台脚本

    其次,因为响应消息是异步的,所以我必须将return设置为true。这是后台脚本消息侦听器等待响应的通知。如果缺少此项,则带有网站内容的响应消息将永远不会在后台脚本中传递

    最后,这导致了一个“一般”问题,而不是问题的直接部分。backgroundscript.js中的chrome.webRequest.onBeforeRequest需要对“cancel”返回值(true/false)进行同步处理,以便做出阻止加载URL的决策。但是要加载内容,总是需要一个异步请求,所以这个问题无法解决?如果我找到解决方案,我将更新此答案


    我希望这个答案也能帮助其他人。

    我也有同样的问题。我确实找到了这个页面,其中讨论了package.json,其中有一个名为cross domain content的特殊“权限”键,但还没有弄清楚它与manifest.json之间的关系。@Sharun这是关于Firefox加载项模型,而不是WebExtensions模型。您的权限配置正确;这不应导致内容脚本代码出现CORS错误。请注意,您的
    getContentByURL
    不会返回任何内容,因为
    get
    是异步的。@Xan ya刚刚意识到了这一点。这里是分机。每次我查找一些东西时,我都会得到附加组件的文档和代码,这会引起一些混乱。现在工作。失踪/是罪魁祸首。@Xan你说得对,我把它移走了。但这并不影响跨原点误差。我用XMLHttpRequest对象修复了它,而不是使用jQuery方法。也许它比jQuery更深入?