at posts/single.html

習作 (2) - データの POST

先日の続き。 今度はデータを POST するサンプル。

<html>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-JP">
<script type="text/javascript" src="xmlhttprequest.js"></script>
<script type="text/javascript">
<!--
function postForm(form) {
  xmlhttp = new XMLHttpRequest();
  if (!xmlhttp) {
    return true;
  }

  xmlhttp.onreadystatechange = function() {
    //読み込み終わったら処理を行う
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
      var disp = document.getElementById('disp');
      disp.innerHTML = xmlhttp.responseText;
    }
  }
  xmlhttp.open('POST', 'post.cgi', true);
  xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xmlhttp.send(getFormData(form));

  return false;
}

function getFormData(form) {
  var value = '';
  for(var i = 0; i < form.elements.length; i++) {
    value += ('&' + form.elements[i].name + '=' + form.elements[i].value);
  }
  return value.substring(1);
}
// -->
</script>
<body>
  <form action="post.cgi" method="post" onSubmit="return postForm(this)">
    <input name="data1" type="text" />
    <input name="data2" type="text" />
    <input type="submit" value="post" />
  </form>
  <div id="disp" style="border: dashed 1px #888; padding: 0.5em"></div>
</body></html>

基本は前回と同じ。 フォームに入力した値を、XMLHttpRequest を使って POST し、結果を disp 領域に表示するようにしている。 Ajax (XMLHttpRequest) が使えない環境でも似たように動くところがポイントかな。

JavaScript の呼び出し

<form action="post.cgi" method="post" onSubmit="return postForm(this)">

form 要素の onSubmit イベントを使って、ボタンが押された時に postForm メソッドを呼び出すようにしている。 ポイントは「return」をつけているところ。

  • postForm の戻り値が false の場合、フォームのデータは送信されない
  • postForm の戻り値が true の場合、フォームのデータが post.cgi に送信される(標準の動作)

XMLHttpRequest が使える環境では、メソッドが false を返すようにしておき、データは XMLHttpRequest で送信する。 逆に使えない環境では、メソッドが true を返すようにし、データをフォームで送信する。 こうすることで、 Ajax 環境でも非 Ajax 環境でもデータを送信できるようになる。

また、メソッドの引数に this (form 要素自身) を指定することで、後述するようにメソッド内にてフォームデータを収集できるようにしている。

フォームデータの収集

postForm メソッドが呼び出している getFormData メソッドで、フォームデータを key1=val1&key2=val2 …の形式に変換している。

※ このスクリプトだと Submit ボタンの値 ("post") も戻り値に含まれてしまう模様。

データの POST

XMLHttpRequest を使ってデータを POST している箇所がここ。

xmlhttp.open('POST', 'post.cgi', true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.send(getFormData(form));

GET の時と違うのは、 open の第一引数が POST になったこと。 それに、 If-Modified-Since ヘッダの代わりに Content-Type ヘッダを付与していること。 このヘッダを明示的に指定しないと、受け取るサーバ側のスクリプトによってはデータが正しく取得できないことがあるようだ(参考: 「XMLHttpRequestのPOSTメソッドにおけるFirefoxとIEの挙動の違い」)。

最後に、 send メソッドでデータを送信している。引数に送りたい (POSTしたい) データを指定する。

サーバ側の動作

ここにはサンプルプログラムは載せなかったけど、当然サーバ側でデータを受け取ってページを返す CGI を用意する必要がある。 このサンプルでは Ajax 環境でも非 Ajax 環境でも同じスクリプト (post.cgi) が呼ばれるので、スクリプト側で環境に応じて返すデータを変えるように作らないといけない。

  • Ajax 環境では、データの送受信は UTF-8 になる。非 Ajax 環境では EUC-JP (HTML の文字コードと同じ) 。
  • Ajax 環境では HTML の一部だけを返せばよい。非 Ajax 環境では HTML 全体を返す。

という違いがある。サーバ側の仕組みはまた後日にでも…。

関連する日記