ajax log

library for log ajax requests and save logs as a file

Tính đến 11-03-2018. Xem phiên bản mới nhất.

Script này sẽ không được không được cài đặt trực tiếp. Nó là một thư viện cho các script khác để bao gồm các chỉ thị meta // @require https://update.greasyforks.org/scripts/39403/257980/ajax%20log.js

// ==UserScript==
// @name        ajax log
// @namespace   https://greasyforks.org/users/174399
// @description library for log ajax requests and save logs as a file
// @version     0.5.0-beta.1.0
// ==/UserScript==

function getNull(arg){return arg || null;}
(function(window){
	try{
	var tracker = {},
		proto = window.XMLHttpRequest.prototype;
	['open', 'send', 'setRequestHeader', 'abort'].forEach(function(m){
		tracker[m] = {
			'original': null,
			'hook': null,
			'ready': null,
		};
	});
	/*function getVal(obj, name){ var c = obj[name] = obj[name] || {}; return c;};*/
	var getVal = function(obj, name){ var c = obj[name] = obj[name] || {}; return c;};
	console.log("tracker: ", tracker);
	/*function setTracker(type, hook)*/
	var setTracker = function(type, hook)
	{
		var t = tracker[type];
		if(!t || t.ready)
			return;
		t.original = proto[type];
		/*t.hook = proto[type] = function()*/
		proto[type] = function()
		{
			hook.apply(this, arguments);
			t.original.apply(this, arguments);
		};
		t.ready = true;
	};
	/*function toObj(str)*/
	var toObj = function(str)
	{
		if( !str )
			return null;
		switch(typeof str)
		{
			case 'object':
			return str;
			case 'string':
			var o = {}, s = str.split('&'), v, p;
			for(p of s)
			{
				v = p.split('=');
				o[v[0]] = v[1] || '';
			}
			return o;
			default:
			return null;
		}
	};
	Object.defineProperty(proto, 'xhrTracker', {
		value: null,
		writable: true,
	});
	proto.xhrTracker = {};
	['addEventListener', 'onreadystatechange', 'onload'].forEach(function(m){
		proto.xhrTracker[m] = {
			'original': null,
			'hook': null,
			'ready': null,
		};
	});
	console.log("prototype: ", proto);
	var responseL = ['response', 'readyState', 'status', 'statusText'];
	/*function setResponse(obj, r)*/
	var setResponse = function(obj, r)
	{
		responseL.forEach(function(n){
			obj[n] = r[n];
		});
	};
	var xhrHook = {
		'onreadystatechange': null,
		'onload': null,
	};
	var flushAndSave = null, totalResponse = '';
	var saveLog = function()
	{
		if( !flushAndSave )
			return;
		console.log("save.totalResponse:\r\n" + totalResponse);
		saveFile('xml-http-request-' + getDate() + '.txt', createFile(totalResponse, 'text/plain'));
		totalResponse = '';
		flushAndSave = false;
	};
	var getHeaders = function(x)
	{
		var headers = x.getAllResponseHeaders(), o = {}, h;
		var hs = headers.split(/\r\n/);
		for(var h of hs)
		{
			h = h.split(': ');
			o[h[0].trim()] = h.slice(1).join(': ').trim();
		}
		return o;
	};
	xhrHook.onreadystatechange = function(e)
	{
		var t = e.target;
		if( t.readyState == 4 )
		{
			var cntx = getVal(t, 'context'),
				o = cntx.onreadystatechange = {};
			setResponse(o, t);
			o.responseHeaders = getHeaders(t);
			o.respHeads = t.getAllResponseHeaders();
			totalResponse += '\r\n\r\n' + JSON.stringify(cntx, null, 2);
			console.log("onreadystatechange.totalResponse:\r\n" + totalResponse);
			saveLog();
		}
	};
	/*function getDate(date)*/
	var getDate = function(date)
	{
		date = date || new Date();
		return '' +
			date.getFullYear() + '-' +
			(date.getMonth() + 1) + '-' +
			date.getDate() + '-@' +
			date.getHours() + '-' +
			date.getMinutes() + '-' +
			(date.getSeconds() * 1e3 + date.getMilliseconds())/1e3;
	};
	console.log("date: ", getDate());
	xhrHook.onload = function(e)
	{
		/*
		var t = e.target,
			cntx = getVal(t, 'context'),
			o = cntx.onload = {};
		setResponse(o, t);
		o.responseHeaders = getHeaders(t);
		totalResponse += '\r\n\r\n' + JSON.stringify(cntx, null, 2);
		console.log("onload.totalResponse:\r\n" + totalResponse);
		saveLog();
		*/
	};
	/*function setXhrTracker(inst, type, hook, original)*/
	var setXhrTracker = function(inst, type, hook, original)
	{
		var t = inst.xhrTracker[type];
		if( t.ready )
			return;
		t.inst = inst;
		console.log("setXhrTracker:" + type + ": ", inst);
		if( typeof original != 'function' )
		{
			t.original = inst[type] || function(){console.log("dummy: " + type);};
			t.hook = inst[type] = function(){
				hook.apply(t.inst, arguments);
				t.original.apply(t.inst, arguments);
			};
		}else{
			t.original = original;
			t.hook = function(){
				hook.apply(t.inst, arguments);
				t.original.apply(t.inst, arguments);
			};
		}
		t.ready = true;
	};
	/*function setEventTracker(inst)*/
	var setEventTracker = function(inst)
	{
		var n = 'addEventListener',
			o = inst.xhrTracker[n],
			i = inst;
		o.inst = inst;
		o.original = inst[n];
		o.hook = inst[n] = function(evt, fun)
		{
			var t = i.xhrTracker['on' + evt];
			if( !!t )
				setXhrTracker(i, 'on' + ev, xhrHook['on' + ev], fun);
			else
				o.original.apply(o.inst, arguments);
		};
	};
	var link;
	var getLocation = function(url, p)
	{
		link = link || document.createElement('a');
		link.href = url;
		return link[p||'href'];
	};
	setTracker('open', function(method, url, async){
		try{
		var cntx = getVal(this, 'context');
		cntx.method = method.toUpperCase();
		cntx.url = getLocation(url, 'href');
		cntx.async = (async === undefined ? null: async);
		console.log("open:context: ", JSON.stringify(cntx, null, 2));
		setEventTracker(this);
		}catch(er){console.error(er);}
	});
	setTracker('setRequestHeader', function(name, val){
		try{
		var cntx = getVal(this, 'context'),
			headers = getVal(cntx, 'headers');
		headers[name] = val;
		console.log("headers:context: ", JSON.stringify(cntx, null, 2));
		}catch(er){console.error(er);}
	});
	setTracker('abort', function(){
		var cntx = getVal(this, 'context');
		cntx.onabort = true;
	});
	setTracker('send', function(data){
		try{
		var cntx = getVal(this, 'context');
		cntx.data = toObj(data);
		console.log("send:context: ", JSON.stringify(cntx, null, 2));
		setXhrTracker(this, 'onreadystatechange', xhrHook.onreadystatechange);
		setXhrTracker(this, 'onload', xhrHook.onreadystatechange);
		}catch(er){console.error(er);}
	});
	var keyboard = function(e)
	{
		if(!e.shiftKey)
			return;
		var code = e.keyCode || e.which,
			ch = String.fromCharCode(code).toUpperCase();
		switch(ch)
		{
			case 'S':
			flushAndSave = true;
			saveLog();
			break;
		}
	};
	window.addEventListener('keydown', function(e){
		keyboard(e);
	});
	function saveFile(name, resource)
	{
		var link = document.createElement('a');
		link.href = resource;
		link.download = name;
		document.querySelector('body').appendChild(link);
		link.click();
		link.parentNode.removeChild(link);
	}
	function createFile(data, type)
	{
		var wu = window.URL || window.webkitURL,
			b = new Blob([data], {type: type}),
			u = wu.createObjectURL(b);
		setTimeout(function(){wu.revokeObjectURL(b);}, 1e4);
		return u;
	}
	}catch(err){console.error(err);}
})(getNull(unsafeWindow) || window);
长期地址
遇到问题?请前往 GitHub 提 Issues。