如何在注入代码中使用GM_xmlhttpRequest?

时间:2012-07-07 17:30:16

标签: javascript google-chrome-extension greasemonkey userscripts

我正在编写一个注入网页的用户脚本。该脚本从Web服务器读取一些数据,我想将消息发送到侦听应用程序以对数据做出反应。

现在,我正在做的就是尝试将一个字符串命令发送到我的监听应用程序,看看我是否可以阅读它。我的代码在注入之前工作,但之后我得到一个“未定义的引用错误”。

我怀疑这与此"Greasemonkey access violation"有关。但是,我一直无法找到有效的解决方案。我正在开发Chrome。

这是我无法工作的代码部分。

GM_xmlhttpRequest({
   method: "POST", 
   url: "http://localhost:7777", 
   data: "testing123",
   headers:  {
         "Content-Type": "application/x-www-form-urlencoded"
             },
   onload: function(response) 
   {
      if (response.responseText.indexOf("TEST") > -1) 
      {
         console.log("Response confirmed..."); 
      }
   }
}); 

我对脚本非常陌生,所以也许我错过了一些明显的东西。如何在注入的代码中使用它?

2 个答案:

答案 0 :(得分:20)

GM_函数在注入的代码中不起作用,因为注入的代码在目标页面的范围内运行。如果他们 在那里工作,那么不道德的网站也可以使用GM_函数来做无法形容的邪恶。

解决方案,最首选:

  1. 不要注入代码。很多时候,它确实没有必要,而且总是让事情复杂化。如果你绝对只注入代码,肯定需要使用目标页面加载的一些javascript。

    对于像jQuery这样的库,您可以使用@require指令(Firefox)获得更好的性能,或粘贴库代码或使用a custom manifest.json file包含它(Chrome)。

    通过不注入代码,您:

    1. 保持轻松使用GM_功能
    2. 的能力
    3. 避免或减少对外部服务器的依赖以提供库。
    4. 避免使用/在页面JS上的潜在副作用和依赖性。 (您甚至可以使用 NoScript 之类的东西来完全禁用页面的JS,而您的脚本仍在运行。)
    5. 防止恶意网站利用您的脚本访问GM_功能。

  2. 使用the Tampermonkey extension(Chrome)。这允许您通过提供更好的Greasemonkey仿真来避免脚本注入。您可以使用@require指令以及比Chrome原生提供的更强大/更有风险的unsafeWindow版本。

  3. 将用户代码拆分为注入的部分 - 不能使用GM_函数 - 和非注入部分。使用messaging,轮询和/或特定DOM节点在范围之间进行通信。



  4. 如果你真的必须使用注入的代码,这里有一个示例脚本,说明如何操作:

    // ==UserScript==
    // @name        _Fire GM_ function from injected code
    // @include     https://stackoverflow.com/*
    // @grant       GM_xmlhttpRequest
    // ==/UserScript==
    /* Warning:  Using @match versus @include can kill the Cross-domain ability of
        GM_xmlhttpRequest!  Bug?
    */
    
    function InjectDemoCode ($) {
        $("body").prepend ('<button id="gmCommDemo">Open the console and then click me.</button>');
    
        $("#gmCommDemo").click ( function () {
            //--- This next value could be from the page's or the injected-code's JS.
            var fetchURL    = "http://www.google.com/";
    
            //--- Tag the message, in case there's more than one type flying about...
            var messageTxt  = JSON.stringify (["fetchURL", fetchURL])
    
            window.postMessage (messageTxt, "*");
            console.log ("Posting message");
        } );
    }
    
    withPages_jQuery (InjectDemoCode);
    
    //--- This code listens for the right kind of message and calls GM_xmlhttpRequest.
    window.addEventListener ("message", receiveMessage, false);
    
    function receiveMessage (event) {
        var messageJSON;
        try {
            messageJSON     = JSON.parse (event.data);
        }
        catch (zError) {
            // Do nothing
        }
        console.log ("messageJSON:", messageJSON);
    
        if ( ! messageJSON) return; //-- Message is not for us.
    
        if (messageJSON[0] == "fetchURL") {
            var fetchURL    = messageJSON[1];
    
            GM_xmlhttpRequest ( {
                method:     'GET',
                url:        fetchURL,
                onload:     function (responseDetails) {
                                // DO ALL RESPONSE PROCESSING HERE...
                                console.log (
                                    "GM_xmlhttpRequest() response is:\n",
                                    responseDetails.responseText.substring (0, 80) + '...'
                                );
                            }
            } );
        }
    }
    
    function withPages_jQuery (NAMED_FunctionToRun) {
        //--- Use named functions for clarity and debugging...
        var funcText        = NAMED_FunctionToRun.toString ();
        var funcName        = funcText.replace (/^function\s+(\w+)\s*\((.|\n|\r)+$/, "$1");
        var script          = document.createElement ("script");
        script.textContent  = funcText + "\n\n";
        script.textContent += 'jQuery(document).ready( function () {' + funcName + '(jQuery);} );';
        document.body.appendChild (script);
    };
    

答案 1 :(得分:0)

您正在发布到本地主机。如果愿意,(并非所有人都会)设置CORS标头,以允许在本地服务器上访问被篡改的站点,或者在所有站点都不安全/被其他人运行/发布时,允许访问所有站点。

然后,只要将XHR正确配置为跨域(您可以通过将其包装在注入的脚本中即可),您根本就不需要使用GM_XHR。