我需要调用跨域GM_xmlhttpRequest
,该域名将由网页中的事件触发。
如何从网页访问greasemonkey沙箱中的功能?
答案 0 :(得分:2)
要允许网页使用GM_xmlhttpRequest
,您必须:
unsafeWindow.XMLHttpRequest
。setInterval
。我以前在本地协议中编写了这样一个供个人使用的用户脚本。 不要滥用,并创建非常严格的匹配模式,以防止跨网站XHR暴露于任意网站。
代码执行以下操作:
XMLHttpRequest
对象移至unsafeWindow.GM_XHR.original
。GM_XHR.restore()
。XMLHttpRequest
对象被自定义方法覆盖,该方法将任何请求添加到数组队列。// ==UserScript==
// @name Cross-site XMLHttpRequest
// @namespace Rob W
// @description Enables cross-site XHR
// @include file:///home/*
// ==/UserScript==
/*
* http://www.w3.org/TR/XMLHttpRequest
* http://wiki.greasespot.net/GM_xmlhttpRequest
* https://developer.mozilla.org/en/XMLHttpRequest
*
* https://developer.mozilla.org/En/nsIDOMProgressEvent
* https://developer.mozilla.org/en/nsIChannel
*/
// Configuration. Allow paths via a RegExp:
var enabled = [
"^file:///home/rob/Documenten/etc/",
"^file:///home/rob/Documenten/test\.html$"
];
var XHR = {
allowed: new RegExp(enabled.join("|")),
allowed_atm: function(url){
return XHR.allowed.test(url || location.protocol + "//" + location.pathname)
},
original: unsafeWindow.XMLHttpRequest,
restore: function(){
unsafeWindow.XMLHttpRequest = XHR.original;
}
};
if (XHR.allowed_atm()) {
// Request queue
var reqs = [];
// Inititate the actual gm_xmlhttpRequest.
// Also define the `.abort()` method
var do_xmlHttpRequest = function(details) {
details.abort = GM_xmlhttpRequest(details).abort;
}
// Set poller, used to circumvent the security policy
window.setInterval(function(){
while(reqs.length) {
do_xmlHttpRequest(reqs.shift());
}
}, 50);
// unsafeWindow.XMLHttpRequest will be overwritten by:
var xmlhttprequest = function() {
var o = {headers: {}},
t = this,
sent = false,
currentHeaders = "";
t.channel = {
name: ""
};
o.onprogress = function(r){
if(r.lengthComputable) {
t.channel.contentLength = r.total;
currentHeaders = "Content-Length: " + r.total;
}
t.status = r.status;
t.statusText = r.statusText;
t.channel.name = r.finalUrl;
};
t.abort = function() {
if(typeof o.abort == "function") o.abort();
else t.onreadystatechange = null;
sent = false;
};
t.getAllResponseHeaders = function() {
return t.responseHeaders ? t.responseHeaders + (/(^|\n)Content-Length:\s?\d/i.test(t.responseHeaders)?"":"\n" + currentHeaders) : currentHeaders;
};
t.getResponseHeader = function(header) {
console_log("Method not supported. getResponseHeader: " + header);
return "";
};
t.open = function(method, url, async, user, password) {
o.method = method;
o.url = url;
t.channel.name = url; //finalUrl?
//o.synchronous = !async; //Not implemented for safety reasons
if (typeof user != "undefined") o.user = user;
if (typeof password != "undefined") o.password = password;
};
t.overrideMimeType = function(mimetype) {
o.overrideMimeType = mimetype;
};
t.send = function(data){
var readyState4reached = false;
if (typeof t.onabort == "function") r.onabort = t.onabort;
if (typeof t.onerror == "function") r.onerror = t.onerror;
o.onload = function(r){
o.onreadystatechange(r);
if (typeof t.onload == "function") t.onload();
};
o.data = data;
o.onreadystatechange = function(r) {
t.channel.name = r.finalUrl;
if (t.responseHeaders = r.responseHeaders) {
var tmp;
if(tmp = t.responseHeaders.match(/Content-Length:\s?(\d+)/i)) {
t.channel.contentLength = tmp[1];
}
}
t.readyState = r.readyState;
t.responseText = r.responseText;
t.status = r.status;
t.statusText = r.statusText;
if(readyState4reached) return;
if(!readyState4reached && t.readyState == 4) readyState4reached = true;
typeof t.onreadystatechange == "function" && t.onreadystatechange();
}
if(!sent) reqs.push(o);
sent = true;
};
t.setRequestHeader = function(name, value) {
o.headers[name] = value;
};
}
/* Event binding */
unsafeWindow.XMLHttpRequest = xmlhttprequest;
unsafeWindow.GM_XHR = {original: XHR.original, restore: XHR.restore};
// Log the exposed method in the console, to not forget about it:
console.log("GM cross-site XHR activated at: " + location.href);
};