Web ページ内の JavaScript プログラム動作中に、 新たにサーバとの非同期通信を開始して表示中のページを動的に変える方式を Ajax とよぶ。以下の HTML 文書と JavaScript プログラムは、ユーザからの入力をCGI経由と Ajax で呼ぶ2つを比較するためのものである。
<!DOCTYPE html> <html lang="ja"> <head> <title>例: Access DB via CGI</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> </head> <body> <h1>DB Access</h1> <h2>via CGI</h2> <form method="POST" action="./db.cgi"> <table> <tr><td>タグ:</td><td><input id="tag" name="tag"></td></tr> <tr><td>数値:</td><td><input id="val" name="value"></td></tr> </table> <p><input type="submit" value="CGIで送信"> / <button id="js-sub" type="button">AJAXで送受信</button></p> </form> <p>Result: <span id="result"></span></p> <p id="all"></p> <script type="text/javascript" src="../src/db-post.js" charset="utf-8"></script> </body> </html>
#!/usr/bin/env ruby22 # -*- coding: utf-8 -*- require 'cgi' require 'json' require 'sqlite3' dbfile = './db/data.sq3' c = CGI.new({'accept_charset' => 'utf-8'}) #print "Content-type: application/json; charset=UTF-8\n\n" print "Content-type: text/plain; charset=UTF-8\n\n" value = c['value'].to_f tag = c['tag'] now = Time.now.to_s db = SQLite3::Database.new(dbfile) db.busy_timeout = 1000 db.execute("CREATE TABLE IF NOT EXISTS foo(tag text, time text, val real);") db.execute("INSERT INTO foo VALUES(?, ?, ?);", tag, now, value) val = {'タグ'=>tag} val['合計'] = db.execute("SELECT sum(val) FROM foo WHERE tag=?", tag)[0][0].to_f val['平均'] = db.execute("SELECT avg(val) FROM foo WHERE tag=?", tag)[0][0].to_f.round(2) res = db.execute("SELECT val FROM foo WHERE tag=?", tag) val['全件'] = res.collect{|row| row[0]} # 先頭カラムを集める puts JSON.pretty_generate(val)
// 例: AJAX的CGI通信 function dbAccess() { function respond(str) { // CGIからの出力応答関数 if (this.readyState == 4) { // 4のときデータ受信完了 // CGIがJSON文字列を返すのでJSON.parseでJSONオブジェクトに変換 var resp = JSON.parse(this.responseText); // 受信文字列取得(JSON) var str = '合計:'+resp['合計'] + ' 平均:'+resp['平均'] var all = '全件: ' + resp['全件'].join(', ') document.getElementById('result').textContent = str; //書き込む document.getElementById('all').textContent = all; } } function submit() { // 「AJAX送信」ボタンを押したときの処理 var val = document.forms[0].elements['value']; var tag = document.getElementById('tag'); if (val) { var conn = new XMLHttpRequest(); conn.open('POST', './db.cgi'); // POSTメソッドでCGIへ送る conn.setRequestHeader( // 送信ヘッダを定義 'Content-Type', 'application/x-www-form-urlencoded'); // 送信データは 変数1=値1&変数2=値2... で送るが、 // 値の部分に&などが入ってもよいよう encodeURIComponent() する conn.send('value='+encodeURIComponent(val.value) + '&' + 'tag='+encodeURIComponent(tag.value)); conn.onreadystatechange = respond; // イベントリスナ登録 } } document.getElementById('js-sub').addEventListener('click', submit); } document.addEventListener('DOMContentLoaded', dbAccess)
db-post.js
のうち Ajax的データ送信を行なうのが
submit
関数である。
XMLHttpRequest
オブジェクトを生成open()
で http でのアクセスメソッド(この場合は
POST)とパスを指定setRequestHeader()
でHTTP送信ヘッダを設定send()
で実データを送信onreadystatechange
プロパティにコールバック関数を代入という流れで行なう。送信するデータはCGIが受け取るためには、
変数1=値1&変数2=値2
のように代入形式の並びを &
記号で区切って必要個数列挙した書式にする必要がある。ただし、変数や値に
=
や &
、空白などの記号が含まれるときに
正しく変数部分と値部分のそれぞれが解釈されるよう、URL
エンコード行なう。URL エンコードは、たとえば空白文字なら
%20
のように % 記号に続けて16進数の文字コードを書くものである。
このエンコードを行なうのが encodeURIComponent
関数である。
CGIプログラムでは、db/data.sq3
をデータベースファイルとして利用するようになっている。
実際に動かす前には、httpd に書き込み可能となるディレクトリを作成し、
そこにダミーのデータベースファイルを作成する。
mkdir -m 1777 db touch db/data.sq3 chmod 666 db/data.sq3
ユーザID、ユーザ名、東経、北緯、
ゴールとなる位置(LatLng)は、goal.txt ファイルに入れておく。