2014年11月2日日曜日

Ajaxを使ったPOSTメソッドによるHTTP通信

◆ 目的
Ajaxの非同期通信を使ったPOSTメソッドによるHTTP通信を実現する。
今更な感があるが、jQueryなどのライブラリを利用する機会が多くなったため、
少しレイヤを下げて、改めて、JavaScriptとDOM(Document Object Model)の
コードを組み合わせた簡易なWEBアプリケーションを構築したくなったしだい。



◆ 動作概要
クライアントが入力フォーム(nameとage)を入力しsendボタンを押すと、
サーバへ非同期にPOST通信を発生させる。
サーバ側がフォームの内容をCGIで処理して実行結果をクライアントへ返答。
サーバからの応答はHTMLコード下段の部分に挿入する。
ページが遷移しないところがポイントである。



◆ HTMLコード
※サーバ設定がないため(CGIが実行できないので)、動作はしない

POST TEST

sample

send form

name:
age:




returning data

name: -
age: -


(実HTML)
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>POST TEST</title>
<link href="post.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="post.js"></script>
</head>
<body>
<h1>POST TEST</h1>
<p>sample</p>
<hr />
<h2>send form</h2>
<form action="post.rb" id="sendForm">
  <div>
    name:
    <input type="text" id="name" name="name" size="30" autocomplete="off" />
  </div>
  <div>
    age:
    <input type="text" id="age" name="age" size="3" autocomplete="off" />
  </div>
  <div>
    <input type="button" name="sendBtn" id="sendBtn" value=“send” />
  <div>
</form>
<hr />
<h2>returning data</h2>
<div>name: <span id="responseName">-</span></div>
<div>age: <span id="responseAge">-</span></div>
</body>
</html>



◆ CGIコード 
#!/usr/bin/ruby
require "cgi"
cgi = CGI.new

name = cgi["name"]
age = cgi['age']

response  = "name\t#{name}\n"
response += "age\t#{age}\n"

puts cgi.header
#puts "Content-Type: text/plain; charset=utf-8";
print "\n"
print response



◆ JavaScriptコード
簡単なコードなので説明は省略。
一部利用しない関数を断りを入れて書いているが、
これはただの自分用メモである。

var httpObj;
var timerId;
var timeoutSec = 10;

function printResData(textData) {
  var i;
  var lines = textData.split("¥n");
  var responseName = document.getElementById('responseName');
  var responseAge  = document.getElementById('responseAge');

  for(i = 0; i < lines.length; i ++) {
    var parts = lines[i].split("¥t");
    var name = parts[0];
    var value = parts[1];
    if(name == 'name') {
        responseName.childNodes[0].nodeValue = value;
    } else if(name == 'age') {
        responseAge.childNodes[0].nodeValue = value;
    }
  }

  document.getElementById('sendBtn').disabled = false;
}


function postData(e) {
  document.getElementById('sendBtn').disabled = true;

  var name = document.getElementById('name').value;
  var age  = document.getElementById('age').value;

  var postData;
  postData = 'name=' + encodeURIComponent(name) +
              '&age=' + encodeURIComponent(age);

  var targetUrl = 'post.rb';

  httpPostRequest(targetUrl, postData, printResData);
}


function httpPostRequest(targetUrl, postData, funcitonReference) {
  try {
    if(window.XMLHttpRequest) {
        httpObj = new XMLHttpRequest();
    } else {
        httpObj = false;
    }
  } catch(e) {
      httpObj = false;
  }
  if(! httpObj) {
    fail();
  }

  timerId = setInterval('timeoutCheck()', 1000);

  httpObj.open("POST", targetUrl, true);
  httpObj.onreadystatechange = function() {
    if (httpObj.readyState == 4) {
      clearInterval(timerId);
      if (httpObj.status == 200) {
        funcitonReference(httpObj.responseText);
      } else {
        alert(httpObj.status + ' : ' + httpObj.statusText);
        return false;
      }
    }
  }
  httpObj.send(postData);
}


function fail() {
  alert("error: your browser is not supported");
  return false;
}


function timeoutCheck() {
  timeoutSec --;
  if(timeoutSec <= 0) {
    clearInterval(timerId);
    httpObj.abort();
    alert('error: timeout');
    return false;
  }
}


function setListeners(e) {
  var sendBtn = document.getElementById('sendBtn');
   // true: capturing(from top), false: bubbling(from bottom)
  addListener(sendBtn, 'click', postData, false);
}


function addListener(elem, eventType, func, cap) {
  if(elem.addEventListener) {
    elem.addEventListener(eventType, func, cap);
  } else {
    fail();
    return false;
  }
}


/* 以下はここでは使わない
function removeListener(elem, eventType, func, cap) {
  elem.removeEventListener(eventType, func, cap);
}


function getElemPos(elem) {
  var obj = new Object();
  obj.x = elem.offsetLeft;
  obj.y = elem.offsetTop;
  while(elem.offsetParent) {
    elem = elem.offsetParent;
    obj.x += elem.offsetLeft;
    obj.y += elem.offsetTop;
  }
  return obj;
}

function getTargetNode(e) {
  var targetNode = e.target;
  return targetNode;
}

function stopDefaultAction(e) {
  e.preventDefault();
}


function stopPropagation(e) {
  e.stopPropagation();
}
*/


addListener(window, 'load', setListeners, false);