[Javascript] Ajaxライブラリ

2016年7月30日

Javascript テクノロジー プログラミング

「jQueryを使えばいいじゃない」とよく言われるが、たかが外部サーバーからデータを取得するだけの事を自分で行えないのが嫌だったので、以前から自作したライブラリを使っていたが、この度、不具合を発見したので、修正版を公開しておきます。

過去の記事

WEBページ内で外部サーバーに設置してあるTEXTファイルを読んだり、書いたりするために、URLに対してデータをリクエストして、返り値を取得した後 イベント処理として関数を実行できるライブラリを作っていた。 [プログラム学習] JavaScript #4 「ファイル読み込み」 [プログラム学習] JavaScript #5 「ファイル書き込み」

改修版

(function(){ var $$ = {}; /** * Ajax */ $$.ajax = { createHttpRequest:function(){ //Win ie用 if(window.ActiveXObject){ try { //MSXML2以降用; return new ActiveXObject("Msxml2.XMLHTTP") } catch(e){ try { //旧MSXML用; return new ActiveXObject("Microsoft.XMLHTTP") } catch(e2){ return null } } } //Win ie以外のXMLHttpRequestオブジェクト実装ブラウザ用; else if(window.XMLHttpRequest){ return new XMLHttpRequest() } else{ return null } }, /** * XMLHttpRequestオブジェクト生成 */ set:function( option ){ if(!option){return} var httpoj = new $$.ajax.createHttpRequest(); if(!httpoj){return} //open メソッド; httpoj.open( option.method , option.url , option.async ); httpoj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //受信時に起動するイベント; httpoj.onreadystatechange = function(){ //readyState値は4で受信完了; if (httpoj.readyState==4){ //コールバック option.onSuccess(httpoj.responseText); } }; //query整形 var data = []; if(typeof(option.query)!="undefined"){ for(var i in option.query){ data.push(i+"="+encodeURIComponent(option.query[i])); } } if(typeof(option.querys)!="undefined"){ for(var i=0;i<option.querys.length;i++){ data.push(option.querys[i][0]+"="+encodeURIComponent(option.querys[i][1])); } } //send メソッド if(data.length){ httpoj.send( data.join("&") ); } else{ httpoj.send(); } }, //コールバック関数 ( 受信時に実行されます ); onSuccess:function(oj){ //レスポンスを取得; var res = oj.responseText; //console.log(res); //ダイアログで表示; if(res && res.match(/^[a-z|$]/)){ eval(res); } } }; //path-info Ex):p=location.href $$.pathinfo = function(p){ var basename="", dirname=[], filename=[], ext=""; var p2 = p.split("?"); var urls = p2[0].split("/"); for(var i=0; i<urls.length-1; i++){ dirname.push(urls[i]); } basename = urls[urls.length-1]; var basenames = basename.split("."); for(var i=0;i<basenames.length-1;i++){ filename.push(basenames[i]); } ext = basenames[basenames.length-1]; return { "hostname":urls[2], "basename":basename, "dirname":dirname.join("/"), "filename":filename.join("."), "extension":ext, "query":(p2[1])?p2[1]:"", "path":p2[0] }; }; $$.urlinfo=function(uri){ if(!uri){uri = location.href} var data={}; //URLとクエリ分離分解; var query=[]; if(uri.indexOf("?")!=-1){query = uri.split("?")} else if(uri.indexOf(";")!=-1){query = uri.split(";")} else{ query[0] = uri; query[1] = ''; } //基本情報取得; var sp = query[0].split("/"); var data={ url:query[0], dir:this.pathinfo(uri).dirname, domain:sp[2], protocol:sp[0].replace(":",""), query:(query[1])?(function(q){ var data=[]; var sp = q.split("&"); for(var i=0;i<sp.length;i++){ var kv = sp[i].split("="); if(!kv[0]){continue} data[kv[0]]=kv[1]; } return data; })(query[1]):[], }; return data; }; /** * 直上の対象エレメントを取得 * param @ elm : target-element * param @ type : [class , id] * param @ value : string **/ $$.getElementByParentNode = function(elm,type,value){ if(!elm){return null} if(type === "class"){ if(elm.parentNode.className.indexOf(value)!=-1){ return elm.parentNode; } else{ return $$.getElementByParentNode(elm.parentNode,type,value); } } else if(type === "id"){ if(elm.parentNode.id && elm.parentNode.id === value){ return elm.parentNode; } else{ return $$.getElementByParentNode(elm.parentNode,type,value); } } }; window.$$LIB = $$; return $$; })();

解説

今回発見した問題点というのは、このAJAX処理を同一ページ内で連続して実行した時に、ライブラリ内で使っている変数が、後から実行した処理が上書きしてしまうという不具合を見つけた。 例えば、複数のリスト型エレメントがあった場合、そのリスト1つずつにサーバーに問い合わせてそれぞれ別の値を返す処理を入れた時に、通常のfor分内でこのajax処理を行なってしまうと、楽勝で結果がバグってしまうのである。 このバグを修正するのは、ぶつかっている変数の「httpoj」の部分をグローバル変数になってしまっているので、これをローカル変数にして、関数が呼ばれる度に完結させなければいけない。 そして、「createHttpRequest」関数をnew演算子を使用して、これにより関数を呼び出す度にインスタンス化されるので、結果グローバルから上書きされることがなくなるのだ。 以前のバージョンと変えたのは、set関数の中身だけで、使い方は互換性をもたせているので、ライブラリを更新するだけでバグが無くなるハズ。

使い方

ajax.set({ url:"http://hoge.com/***.php", //対象URL methos:"post", //POST or GET async:true, //true or false query:{"data":"abcdefg"}, //queryをjson記述で書ける。 onSuccess:function(res){console.log(res)} }); 上記をサンプルとして、適宜内容を変更することでサーバー通信が可能になる。 今回のライブラリ改修で、連続アクセスも可能になるので、より強固なライブラリになったという事だ。 なんか、バグが治って、少しうれしい・・・

追記 : 送信Query仕様

POST送信を行う場合にQuery情報の登録方法は2通りの仕様を採用しています。

1. 配列方式

Ex) querys:[ “aa[]=1” , “aa[]=2” , “aa[]=3” ] この方法のメリットは、PHPサーバーへのクエリ送信を行う場合にExの様に同じkey名をセットする事ができます。

2. オブジェクト方式

Ex) quert:{ “aa”:1 , “bb”:2 , “cc”:3 } スタンダードな方法なので、通常はこちらを使うほうが分かりやすいかもしれません。

注意点

クエリ設定を行なってmethodを「GET」にすると、ライブラリ内で自動的にURLにクエリを追加する方式になりますが、古いブラウザなどは数KbのURLしか対応していないものもあるので、長文送信の場合はPOSTで行いましょう。 また、urlの箇所にGET記述を行う場合は、POST設定を行なってもurl部分はGET記述で送信されます。 これはサーバーセキュリティでPOSTとGETを切り分けている場合を想定しているので、ライブラリでの対応範囲を広げるための処置なので、ご自身で切り分けてご使用ください。

ajax処理で不具合を見つけたので改修をしました。

issue

「content-type」が「application/x-www-form-urlencoded」に固定されている。

dealing with

optionに「type」を追加して、「content-type」を個別にセットできるようにした。 ※デフォルト(指定なし)は「application/x-www-form-urlencoded」

source

$$.ajax = { createHttpRequest:function(){ //Win ie用 if(w.ActiveXObject){ //MSXML2以降用; try{return new ActiveXObject("Msxml2.XMLHTTP")} catch(e){ //旧MSXML用; try{return new ActiveXObject("Microsoft.XMLHTTP")} catch(e2){return null} } } //Win ie以外のXMLHttpRequestオブジェクト実装ブラウザ用; else if(w.XMLHttpRequest){return new XMLHttpRequest()} else{return null} }, /** * XMLHttpRequestオブジェクト生成 */ set:function(option){ if(!option){return} var httpoj = new $$.ajax.createHttpRequest(); if(!httpoj){return;} //open メソッド; httpoj.open( option.method , option.url , option.async ); if(typeof option.type != "undefined"){ httpoj.setRequestHeader('Content-Type', option.type); } else{ httpoj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); } //受信時に起動するイベント; httpoj.onreadystatechange = function(){ //readyState値は4で受信完了; if (httpoj.readyState==4){ //コールバック option.onSuccess(httpoj.responseText); } }; //query整形 var data = []; if(typeof(option.query)!="undefined"){ for(var i in option.query){ data.push(i+"="+encodeURIComponent(option.query[i])); } } if(typeof(option.querys)!="undefined"){ for(var i=0;i<option .querys.length;i++){ data.push(option.querys[i][0]+"="+encodeURIComponent(option.querys[i][1])); } } //send メソッド if(data.length){ httpoj.send( data.join("&") ); } else{ httpoj.send(); } }, //コールバック関数 ( 受信時に実行されます ); onSuccess:function(res){console.log(res)} }; $$.ajax.set({ "url" :scriptPath + "service/protech/js/common.js", "method":"get", "async" :"true", "type" :"text/plain", "onSuccess":function(res){ eval(res); } });

注意点

type指定する時は、methodを「get」にしてください。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。