Page No.1

この記事は公開または最後に更新されてから523日が経過しています。情報が古くなっている可能性があるのでご注意下さい。

だいたいエラーというものは、唐突に思わぬところで発生しているもの。
先日もそんなエラーが、Edge で発生していたわけなのだけれど。
いまやほとんど Edge をさわらなくなっていることと、トップページ以外で発生していたのでまったく気が付かなかったというていたらくなありさま。
で、やはりちゃんとエラーが発生したときの対処をしていないといけないのだけれど、なにゆえにいままであまり関心がなかったのか、我ながら不思議なところではあったりして。
と、いうところで、さて javascript の場合はどうすれば?ということになる。
例外処理というとやはり try...catch 文というのは頭にある・・・。新しく付け加えた部分だとか、どうもここは怪しい!のでは?というところがわかっているなら、あらかじめその部分を try...catch 文に仕込んでおくということなのだろうけれど。しかるに、それなりにテストを重ねた上で、これで大丈夫だと思っているわけなのでエラーは思わぬところで発生するということになってしまうのでありますね。それゆえにその思わぬところで発生するものを把握するには、すべての部分において網を張っておくしかないということになる。
であれば、その try...catch に、全文を仕込んでしまっていいのだろうか?などという、素朴な疑問に突き当たってしまうわけなのでありますねこれが。それとも手当たりしだいにいたるところに、仕込みまくってしまうのか? try...catch は負荷が大きいという記事もあったりするし。
それやこれやでじたばたしていると、いよいよ遭遇したのが window.onerror 。なんだ、ちゃんとあるじゃん。ってか!
取得できないエラーもあるようだけれど、とりあえずはこの window.onerror が使えそうなのでやってみることにしませう。
«MDN web docs»によると

window.onerror = function( message, source, lineno, colno, error ) {}
    message: error message (string)).
    source: URL of the script where the error was raised (string)
    lineno: Line number where error was raised (number)
    colno: Column number for the line where the error occurred (number)
    error: Error Object (object)
JavaScript
CopyExpand

と、いうことである。
では、これによって得られる情報をどうしましょうか。
ログにするのもいいけれど、ログもなんやかんやでいろいろあってわざわざ見るのも面倒になるし、できればリアルタイムで知ることができればありがたい!ということもあるので、メールにて知らせるということにした。
WordPress Ajax 機能を使って、 javascript からデータを php に送ってメールを送信しようという目論見。まぁ、そのあたりは他のことで使いなれていることなので特に問題なく事は進みそう。
と、いうことでまずは javascript 側の処理から。
jQuery でもjQuery の囲みの外に書けばこのまま動きます。wpajax_send関数は別にしなくても良いのだけれど、このajax の部分だけを独立させておけば、他の事で使いまわしができる。
そのajax の部分で重要なのは23~26行目あたり。WordPress ajax の作法。wpajaxurl で指定するのは、/wp-admin/admin-ajax.php。実際に送信するデータにおいて、action で指定するのは、受信側であるphp のフックの名前、wp_ajax_{} の{}の文字列。これらはWordPress におけるajax でのきまりごと。詳しくはcodex などご覧あれ。
ip アドレスとかブラウザの情報は無くても良さげではあるけれど、特に、その時ページにアクセスしていたip アドレスの方は必要な情報だと思う。実際に稼働させているとエラーを出しているのはgoogle のbot ばかりだったりした。

window.onerror = function( message, source, lineno, colno, error ) {
	/*
	message: error message
	source: error file path
	lineno: error line number
	colno: column number
	error: error object
	*/
	var strsend = message + ':' + source + ':' + lineno;

	wpajax_send( strsend );
}

function wpajax_send( target ) {
	var curhost = location.hostname;
	if ( 'localhost' != curhost ) {
		// phpにおいて予めアクセスしているip-address を仕込んである-><input type="hidden" value="ip-address">
		var tarip = document.mainfrm.testword.value,
			cururl = curhost + location.pathname,
			mybrowse = whatbrowse();
		
		// WordPress のフォルダにある/wp-admin/admin-ajax.php を指定
		var wpajaxurl = 'https://strix.main.jp/wp/wp-admin/admin-ajax.php',
			strsend = [
				'action=jserrmsg',
				'target=' + cururl + ':' + tarip + ':' + target + ':' + mybrowse
			];

		var req=new XMLHttpRequest();

		req.open( 'POST', wpajaxurl, true );
		req.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
		req.send( strsend.join( '&') );
	}

}

function whatbrowse(){
	var userAgent = window.navigator.userAgent.toLowerCase(),
		ans = '';

	if ( userAgent.indexOf( 'msie' ) != -1 ) {
		ans = 'ie old';
	} else if ( userAgent.indexOf( 'edge' ) != -1 ) {
		ans = 'edge';
	} else if ( userAgent.indexOf( 'opera' ) != -1 ) {
		ans = 'opera';
	} else if ( userAgent.indexOf( 'safari' ) != -1 ) {
		ans = 'safari';
	} else if ( userAgent.indexOf( 'chrome' ) != -1 ) {
		ans = 'chrome';
	} else if ( userAgent.indexOf( 'firefox' ) != -1 ) {
		ans = 'fox';
	} else if ( userAgent.indexOf( 'iphone' ) != -1 ) {
		ans = 'iPhone';
	} else if ( userAgent.indexOf( 'ipad' ) != -1 ) {
		ans = 'iPad';
	} else if ( userAgent.indexOf( 'android' ) != -1 ) {
		if ( userAgent.indexOf( 'mobile' ) != -1 ) {
			ans = 'android sm';
		} else {
			ans = 'android tb';
		}
	} else if ( userAgent.indexOf( 'trident' ) != -1 ) {
		ans = 'ie new';
	} else {
		ans = 'unknown';
	}
	return ans;
}
JavaScript
CopyExpand

そして、受信する側のphp のfunctions.php。
送信先のメールアドレスは、まぁ、わかっているだろうからわざわざget_option で取得する必要がないことは言うまでもなく。重要なのは先述もしているけれど、add_action においてのフックの名前、wp_ajax_{} の{}の文字列指定。
ブラウザ判別はこれでいいのかいまひとつ確信なし。Opera などはとれていないように思ったが・・・?まっ!ほとんどchrome と同じだろうから大した問題でもなさそう。

function jserrmsg() {

	if ( isset( $_POST['target'] ) ) {
		$cdt = date( 'Y/m/d H:i:s' );
		$title = 'Javascript Error Happens';
		$sendstr = $cdt . ':' . $_POST['target'];
		wp_mail ( get_option( 'admin_email' ), $title, $sendstr );
	}
}
add_action( 'wp_ajax_jserrmsg', 'jserrmsg' );
add_action( 'wp_ajax_nopriv_jserrmsg', 'jserrmsg' );
PHP
CopyExpand

と、いうことで早速、冒頭に書いているEdge のエラーにおいて試してみたのです。が・・・。
コンソールにはエラーの内容が表示されている。
Unable to get property 'style' of undefined or null
そして、その下にもう一つ赤い文字でこんなエラーが・・・。
HTTP403: 禁止されています - サーバーは要求を理解しましたが、その要求の処理を拒否しています。 (XHR)POST - admin-ajax.php
なんだこりゃ?って感じ。
403だけどForbidden はついてないし。それに、禁止されています、と言いつつもなんだか言い訳がましい。「その要求を拒否しています」って、禁止されているのなら要求を拒否もないだろう、と思うのだけれど。なんかうさんくさいというか怪しげである。
で、ローカルな環境で同じエラーが発生するようにして試してみると、その403エラーが出ることはなく、あっけらかんと問題なく実行されてしまう。ちなみにローカルではメール送信ではなくログファイル書き込みにて行いました。
ならばと、発生するエラーの種類を変えて(エラーメッセージの内容が変わるようにして)、Webサーバーの方で試してみるとエラーが出ることはなくちゃんとメールが送信される。さらに、元のエラーに戻したのち、エラーメッセージを省略するとか、エラーがあったことだけを知らせる単純な文字列に代えるとかしてやってみると、それらも問題なく動いてしまう。
これはいったい?!と。
単純にメッセージの内容で判断して拒否しているようだ。いったいそんな設定がサーバーにあるのだろうか?いや~、存じ上げませぬ。
やはりエラーメッセージはあったほうがわかりやすいし、それならエラーメッセージを暗号化すればどうだろうか、と。で、すぐに思いついたのはアルファベットを指定文字数だけずらすシーザー暗号ってやつ。コードを書くのも簡単そうだし。
やってみると、思ったとおり、これがまんまと普通に送信できてしまった。そして、解読用のページなども仕込んでしめしめと・・・。
しかし、ふと、こんな面倒なことをしなくとも、ただ読めなくすればよいのなら、文字列に記号をはさみこむとかするだけでいいんじゃないかと考えたりして。例えば読みやすいようにスペースとかね。
と、いうことで実際にエラーメッセージにスペースをはさみこむ手法でやってみると、それで問題なく送信してくれたってわけですね~!以下のごとく。

2017/5/19:追記

しかし、実はもう一つ対処しておかないといけないことがあった。
たとえば、スクロールイベントなどにエラーが潜んでいたとする。そうなると排出されるエラーというのが、あっというまにものすごい数になってしまうのです。それにより送信されるメールの量もびっくりする数になり、サーバーで止められちゃたりして、ご迷惑をおかけするということにもなってしまう。おごめん。
と、いうことでそのあたりの処理を追加しています。連続してエラーが発生した場合は、メール送信を待たせて、区切りが付いたところで、エラーメッセージを一つにまとめて送信させるという具合。

let happendErrorList = [],
	happendErrorSendID = null;

window.onerror = function ( msg, file, line, column, err ) {
	/*
	msg: error message
	file: file path
	line: row number
	column: column number
	err: error object
	*/ 

	let msg_ary = msg.split(''),
		msg_len = msg_ary.length,
		new_str = '',
		strsend;

	for ( let i = 0; i < msg_len; ++i ) {
		new_str += msg_ary[ i ] + ' ';
	}

	strsend = new_str + ' : ' + file.replace( 'https://strix.main.jp/wp-content/themes/first/', '' ) + ' : ' + line;

	const now = new Date(),
		nowstamp = now.getTime(),
		list_len = happendErrorList.length,
		// あまりにエラーが続くようならメール送信待ち時間を3分に伸ばす
		interval = list_len > 50 ? 180000 : 30000;

	// あまりにエラーメッセージが溜まってしまった場合に一度数を10個にへらす
	if ( list_len > 500 ) {
		happendErrorList.length = 10;
	}

	// '\u0001'はデリミタ
	happendErrorList.unshift( nowstamp + '\u0001' + strsend );

	clearTimeout( happendErrorSendID );

	happendErrorSendID = setTimeout( function() {
		if ( happendErrorList[1] ) {
			strsend = happendErrorList.join( "\n" );
			
			// メールを送信したら溜まったエラーメッセージを消去
			happendErrorList.length = 0;
			wpajax_send( strsend );
		} else {
			happendErrorList.length = 0;
			wpajax_send( strsend );
		}
	}, interval );
}

JavaScript
CopyExpand

さぁ、これではたしてjavascript のエラーを収集できるだろうか?とはいうものの、そんなエラーメッセージメールなんてのは無いに越したことはないんだけれどね。
それでも意に反していくつかそんなメールは現れるわけなのだけれど、いまのところそのほぼ全てがgoogle bot によるもの。それとは違うものはIron というブラウザによるある特定のipによるアクセスに限られる。
goolge bot によるエラーは、不思議なことにその全てにおいてjavascript ファイルが古いバージョンのものでのこと。そりゃ、古い日付のものを使われていたら当然のこと発生するであろうと思われるエラーである。とは思うものの、しかし、それなら最新のバージョンにしかない機能である、エラーメッセージメールが送信されるのはどういうことなのだろうか、と。よくわからない。とりあえずキャッシュされている古いものも使いつつ、新しい日付指定のファイルを見つけるとそれを読み込んで実行しなおすということなのだろうか。そして新しい方をキャッシュしなおすと。そうであれば、もう、エラーの出る古いものは使用されないはずであるから、放おっておけば良いように思われる。はたして・・・!

・・・

Leave a Reply!

JavaScript is necessary to send a comment.
You can edit and delete your comment if you input a edit key.
Edit key is necessary for attesting you when you edit and delete it.
The tag of HTML cannot be used in comment.
When you comment for the first time, it is displayed after the approval of the administrator.
Because I cannot speak English so much, it takes time to answer.
Required fields are marked *.

※Please enter more than 5 characters only alphabets.
※Edit or delete are possible for 2000 days after approval.

*

♠Simplistic Comment User Editable v4.0

♠When visitors leave comments on the site this site collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
♠This site does not use cookie when visitors leave comments and commenter edit comment.
♠This site uses Akismet to reduce spam. Learn how your comment data is processed.

Comments feed

Trackback URL : https://strix.main.jp/wp-trackback.php?p=157161

Sanbanse Funabashi

Top

スクロールさせるか画像をクリックすると元に戻ります。