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

aka*_*xer 8 javascript greasemonkey userscripts google-chrome-extension

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

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

我怀疑这与"Greasemonkey访问违规"有关.但是,我一直无法找到有效的解决方案.我正在开发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..."); 
      }
   }
}); 
Run Code Online (Sandbox Code Playgroud)

我对脚本很新,所以也许我错过了一些明显的东西.如何在注入的代码中使用它?

Bro*_*ams 21

GM_函数将无法在注入的代码中工作,因为注入的代码在目标页面的范围内运行.如果他们那里工作,那么肆无忌惮的网站也可以使用这些GM_功能 - 做出无法形容的邪恶.

解决方案,最首选:

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

    对于像jQuery这样的库,您可以使用@require指令(Firefox)获得更好的性能,或粘贴库代码或使用自定义manifest.json文件来包含它(Chrome).

    通过不注入代码,您:

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

  2. 使用Tampermonkey扩展程序(Chrome).这允许您通过提供更好的Greasemonkey仿真来避免脚本注入.您可以使用该@require指令以及unsafeWindow比Chrome原生提供的功能更强大/风险更高的版本.

  3. 将用户脚本代码拆分为注入的部分(不能使用GM_函数)和非注入部分.使用消息传递,轮询和/或特定DOM节点在作用域之间进行通信.



如果你真的必须使用注入的代码,这是一个示例脚本,显示如何执行它:

// ==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);
};
Run Code Online (Sandbox Code Playgroud)