7

我正在寫入注入到網頁的用戶腳本。該腳本從Web服務器讀取一些數據,並且我想將消息發送到偵聽應用程序以對數據作出反應。如何在注入代碼中使用GM_xmlhttpRequest?

現在,我所做的就是試圖向我的偵聽應用程序發送一個字符串命令,看看我能否讀取它。我的代碼在它被注入之前工作,但是之後我得到一個「未定義的引用錯誤」。

我懷疑這與"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..."); 
     } 
    } 
}); 

我對腳本很陌生,所以也許我錯過了一些明顯的東西。我如何得到這個在注入代碼中工作?

+0

Chrome版本?你可以顯示你的元數據塊('/ == == UserScript ==')嗎? – 2012-07-07 21:49:38

+0

我正在開發它的鉻。我沒有分發它或任何東西。就我現在正在做的事情而言,所以元數據並不意味着什麼。 – akagixxer 2012-07-07 21:50:11

回答

15

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); 
}; 
+0

謝謝!這給了足夠的工作和解決問題。我不得不使用注入的代碼。在未來,我希望找到一個更優雅的解決方案,但由於我對網頁腳本的知識有限,現在這種方法很有用。 – akagixxer 2012-07-13 15:49:29