如何在Chrome扩展中使用AJAX发送POST请求?

4
我正在尝试在浏览器访问我的网页时进行ajax调用,它可以完美地工作,但是一旦离开我的域名,它就会失败。这是针对一个用户知道他们正在被跟踪的封闭系统,所以没有任何可疑的事情发生。我在域名之外的所有内容上都收到错误406。例如,如果我在我的网址www.mywebpage.com上,脚本执行得非常完美,但是一旦我访问www.yourwebpage.com,它就会返回错误。
我已经尝试将manifest.json中的权限设置为我的URL、所有URL、特定URL,但它的行为方式都是相同的。这是我的background.js。
chrome.runtime.onMessage.addListener
(
    function(message, sender, sendResponse) 
    {
        if(message.applicationcode=="VALIDAPPLICATIONKEY")
        {
            var salt=message.salt;
            var learnerid=message.learnerid;
            var behaviorkey=message.behaviorkey;
            var behaviorname=message.behaviorname;
            var behaviorkeyname=message.behaviorkeyname;
            chrome.tabs.query
            (
                {active: true}, 
                function(arrayOfTabs) 
                {
                    var data = new FormData();
                    data.append('Salt', salt);
                    data.append('LearnerID', learnerid);
                    data.append('BehaviorKey', behaviorkey);
                    data.append('BehaviorName', behaviorname);
                    data.append('BehaviorKeyName', behaviorkeyname);
                    data.append('BehaviorValue', arrayOfTabs[0].url);
                    var xhr = new XMLHttpRequest();
                    xhr.open('POST', 'https://www.mywebpage.com/myservice.php', true);
                    xhr.onreadystatechange = function() 
                    {
                        if (xhr.readyState == 4) 
                        {
                            // JSON.parse does not evaluate the attacker's scripts.
                            var resp = JSON.parse(xhr.responseText);
                            console.log(resp);
                        }
                    }
                    xhr.send(data);     
                }
            );//end query
            return true;
        }
    }
);//end listener

这是我的当前清单文件。

{
    "manifest_version": 2,
    "name": "Application",
    "description": "Plugin",
    "version": "1.0",
    "background": 
    {
        "scripts": ["jquery.js","background.js"],
         "persistent": true
    },
    "permissions": [
        "tabs","http://www.mywebpage.com/*","https://www.mywebpage.com/*"

    ],
    "browser_action": 
    {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },
    "content_scripts": 
    [
        {
            "matches": ["<all_urls>"],
            "js": ["jquery.js","popup.js"]
        }
    ]
}

非常感谢您的帮助和建议。根据这里的文档,我想做的事情是允许扩展程序并且在有限的情况下确实可以工作。或者,是否应该像这里建议的那样,在扩展程序页面上执行此类操作?我刚开始编写Chrome扩展程序,肯定会漏掉一些愚蠢的东西。

提前致谢。


1
你的清单文件在这里非常关键。 - Xan
在你链接的答案中 resp === sendResponse,所以实际上调用了 sendResponse。但是你的代码中没有使用它。 - Xan
这很有道理。我最开始使用的是sendResponse,但由于这个问题我改了。 - ProgrammerWannabe
1
使ajax从后台而不是内容中进行。 - Zig Mandel
1
Ajax请求来自后台。 - ProgrammerWannabe
显示剩余3条评论
2个回答

10

这是我的解决方案:

manifest.json:

{
    "manifest_version": 2,
    "name": "My Name",
    "description": "My Description.",
    "version": "0.1",
    "background": 
    {
        "scripts": ["jquery.js","background.js"],
        "persistent": true
    },
    "permissions": 
    [
        "tabs",
        "storage"
    ],
    "browser_action": 
    {
        "default_icon": "icon.png",
        "default_popup": "popup.html"
    },
    "content_scripts": 
    [
        {
            "matches": ["https://www.myurl.com/*"],
            "js": ["jquery.js","popup.js"],
            "run_at": "document_end"
        }
    ]
  }

background.js:

var learnerid=0;
// Called when the user clicks on the browser action.
chrome.tabs.onUpdated.addListener
( 
    function (tabId, changeInfo, tab) 
    {
        if (changeInfo.status == 'complete') 
        {
            chrome.tabs.query
            (
                { 
                    active: true 
                }, 
                function (tabs) 
                {
                    if(learnerid!=0)
                    {
                        TrackURL(tabs);
                    }
                    else
                    {
                        console.log("User not logged in yet!");
                    }//end if
                }
            );//end query
        }
    }
);

chrome.runtime.onMessage.addListener
(
    function(message, sender, sendResponse) 
    {
        if(message.applicationcode=="appname")
        {
            learnerid=message.learnerid;
        }//end if
    }
);//end function


function TrackURL(tabs)
{
    $.ajax
    (
        {
            type: "POST",
            url: "http://www.myurl.com/action.php",
            dataType:"json",
            data: 
            {               
                Action: 'TrackURL',
                URL:tabs[0].url,
                Title:tabs[0].title,
                LearnerID:learnerid
            },
            success: function(msg)
            {
                console.log("URL Tracked");
            }//end function
        }
    );//End ajax 

}//end function

弹出框.js:

document.addEventListener
(
    "starttrack", 
    function(e) 
    {
        startPoll(e.detail);
    }
); 


function startPoll(e)
{
    chrome.runtime.sendMessage
    (
        {
            applicationcode: "myapp",
            learnerid: e,
        }
    ); 
}

从我的网页:

function SendLearnerID(value)
                  {
                    try
                    {

                        var event = new CustomEvent("starttrack",{'detail': value});
                        document.dispatchEvent(event);
                    }
                    catch(err) 
                    {
                        console.log(err);
                    }   

                  }//end function

我的问题在于我的原始事件调用发生在网页内部...因此出现了406错误。希望这能帮助其他人。


1

原因:

幸运的是,您是正确的... 您只是缺少一些简单的东西:

您需要为您希望此功能在其中工作的任何和每个页面/域名/URL获取权限,而您当前的manifest.json中仅请求了对www.mywebpage.com的权限:

    "permissions": [
      "tabs","http://www.mywebpage.com/*","https://www.mywebpage.com/*"
    ],

解决方案:

如果您想在背景页/脚本中进行此操作,则需要在manifest.json中的permissions条目中添加所有URL。 如果您想从内容脚本中执行此操作,则需要将其添加到content_scripts条目中。 如果您计划在两个地方都执行此操作,则在两个条目/部分中均添加:

    "permissions": [                //needed for background script
      "tabs","http://*/*","https://*/*"
    ],
    "content_scripts":[             //needed for content script
      ...
      "http://*/*","https://*/*"
      ...
    ]

如果您希望用户在打开本地文件时也能使用您的扩展程序,那么请添加文件模式/协议的权限,如下所示:
    "permissions": [                //needed for background script
      "tabs","http://*/*","https://*/*","file://*/*"
    ],
    "content_scripts":[             //needed for content script
      ...
      "http://*/*","https://*/*"
      ...
    ]

1
老实说,我不喜欢这个答案。如果像描述的那样从“后台页面上下文”发送XHR,则这不应该是问题所在。 - Xan
1
@Xan:不正确。如果您正在使用后台页面,则需要权限。如果您正在使用内容脚本,则也需要在那里设置它们。 - Flak DiNenno
2
这是完全错误的。对于从后台脚本上下文执行的XHR,document.location.href与任何打开的页面无关(确切地说,它是chrome-extension://[extension id here]/_generated_background_page.html)。只要请求地址有主机权限,这样的XHR就不必担心跨域问题。OP实际上链接到了相关文档 - Xan
2
实际上,内容脚本文档 表示它们允许跨源请求,其策略与后台页面相同。 - Xan
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接