【问题标题】:How to use GM_xmlhttpRequest in Injected Code?如何在注入代码中使用 GM_xmlhttpRequest?
【发布时间】:2012-07-07 19:08:02
【问题描述】:

我正在编写一个注入网页的用户脚本。该脚本从 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..."); 
      }
   }
}); 

我对脚本很陌生,所以也许我遗漏了一些明显的东西。如何让它在注入的代码中工作?

【问题讨论】:

  • Chrome 版本?你能展示你的元数据块(//==UserScript==)吗?
  • 我正在为 chrome 开发它。我没有分发它或任何东西。只是我现在自己在做的事情,所以元数据没有任何意义。

标签: javascript google-chrome-extension greasemonkey userscripts


【解决方案1】:

GM_ 函数在注入代码中不起作用,因为注入代码在目标页面的范围内运行。如果他们确实在那里工作,那么不道德的网站也可以使用GM_ 功能——做不可言喻的邪恶。

解决方案,最好是优先:

  1. 不要注入代码。很多时候,它真的没有必要,而且它总是使事情复杂化。仅在您绝对肯定需要使用目标页面加载的某些 javascript 时才注入代码。

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

    通过不注入代码,您:

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

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

  3. 将您的用户脚本代码拆分为注入部分(不能使用GM_ 函数)和非注入部分。使用messaging、轮询和/或特定的 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);
};

【讨论】:

  • 谢谢!这足以解决问题。我必须使用注入代码。将来我希望找到一个更优雅的解决方案,但鉴于我对 Web 脚本的了解有限,目前这将非常有用。
  • 这只是我需要的一半,我还需要让消息传递以另一种方式工作,并使其成为 $.ajax 的普遍下降。这开始看起来很恶心。
  • @RyanTheLeach,这并不容易。除了上述之外,您还可以调度自定义事件和/或exportFunction a helper function 或两个。
  • 我设法解决了我的问题,因为我控制了我试图代理的服务器,只需设置一些 CORS 标头,很简单!出于某种原因,我的脑海中倒退了 CORS,认为被篡改的站点需要允许我的站点访问。 exportFunction 一个助手 + 自定义事件本来是要走的路,在查看之后。
【解决方案2】:

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

那么您根本不需要需要使用 GM_XHR,只要将 XHR 正确配置为跨域即可,您可以通过将其包装在注入的脚本中来实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    相关资源
    最近更新 更多