2012年6月26日火曜日

Node.js+expressをとりあえず試してみた

朝からインストールをしたNode.jsですがいろいろ見ていてもしょうがないので
とりあえず試しに動かしてみました。

Node.js恒例?のチャットアプリ。

Socket.IOを使うのかなって思ってましたがexpressでできそうなのでまずそれをインストールします。
$ npm install express

次にexpressには最低限必要となるファイル等があるみたいです。
それらを生成する必要がありますが自動的に生成してくれるコマンドがあります。
$ node node_modules/express/bin/express chatsample

こうすることでchatsampleというディレクトリが生成され、実行環境が整います。
さらにもうひとつ。expressに依存するモジュールもついでにインストールします。
$ cd chatsample
$ npm install

これでOK。

とりあえず動かしましょう。http://127.0.0.1:3000/
$ node app.js

こんな画面がでればOK。
中身を見てみるとjadeというNode用?のテンプレートエンジンを使って表示されているのがわかります。
とりあえずややこしいのでここでは使いませんが。。。

これからチャットアプリを作成していくわけですが、初心者なんでほとんどサンプルのままです。。。

app.js
var express = require('express')
  , routes = require('./routes')
  , http = require('http');

var app = express();

app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.use(express.favicon());
    app.use(express.logger('dev'));
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(app.router);
    app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
    app.use(express.errorHandler());
});

// メッセージを管理するオブジェクト
var messageStore = {
    _messages: [],
    _listeners: [],

    // メッセージを追加
    addMessage: function(entry) {
        this._messages.push(entry);
        if (this._messages.length > 20) {
            this._messages = this._messages.slice(1);
        }

        for (var key in this._listeners) {
            this._listeners[key]();
            delete this._listeners[key];
        }
    },

    // メッセージを受け取ったある通知するコールバックを登録
    listenOnce: function(listener) {
        this._listeners.push(listener);
    },

    // メッセージを取得
    getMessages: function() {
        return this._messages;
    }
};

app.get("/", routes.index);

// メッセージの読み込みを受け付ける
app.get("/message", function(req, res) {
    res.header("content-type", "text/javascript");

    if (req.url == "/message") {
        // すぐにメッセージを返す
        res.end(JSON.stringify(messageStore.getMessages()));
    } else {
        // 新しいメッセージがくるまで待つ
        messageStore.listenOnce(function() {
            res.end(JSON.stringify(messageStore.getMessages()));
        });
    }
});

// メッセージの書き込みを受け付ける
app.post("/message", function(req, res) {
    var entry = {
        name: req.body.name,
        message: req.body.message,
    };

    messageStore.addMessage(entry);

    res.status = 202;
    res.send("message received");
});

http.createServer(app).listen(app.get('port'), function(){
    console.log("Express server listening on port " + app.get('port'));
});

次に画面です。public/chat.html
<!DOCTYPE HTML>
<html>

<head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="/stylesheets/style.css">
    <title>Chat with Node.js</title>
</head>

<body>
<h1>Chat with Node.js</h1>

<form id="form" action="">
    <input type="text" name="name" id="name" size="10">
    <input type="text" name="message" id="message" size="60">
    <input type="submit" value="send" id="send">
</form>

<hr>
<div id="chat"></div>

<script type="text/javascript" src="/javascripts/client.js"></script>

</body>

</html>

最後にクライアント側のJS。public/javascripts/client.js
var connect = window.addEventListener
                ? function(element, type, callback) { // IE以外
                    element.addEventListener(type, callback, false);
                }
                : function(element, type, callback) { // IE
                    element.attachEvent("on" + type, function() {
                        return callback(window.event);
                    });
                };

var createXHR = XMLHttpRequest
                ? function() {
                    return new XMLHttpRequest();
                }
                : function() {
                    return new ActiveXObject("MSXML2.XMLHTTP.6.0");
                }

// ページが読み込まれたら呼び出される
connect(window, "load", function() {
    var nameInput = document.getElementById('name'),
        messageInput = document.getElementById('message'),
        sendMessage = function() {
            var data = "name=" + encodeURIComponent(nameInput.value)
                        + "&message=" + encodeURIComponent(messageInput.value),
                    xhr = createXHR();

            xhr.open("POST", "message", false);
            xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
            xhr.send(data);
        };

    var f = document.getElementById('form');

    connect(f, "submit", function(event) {
        sendMessage();
        messageInput.value = "";
        if (event.preventDefault) {
            event.preventDefault();
        }

        return false;
    });

    loop(true);
});

// メッセージを受け取るループ処理
function loop(isFirst) {
    var xhr = createXHR(),
        query = isFirst ? "" : ("?" + new Date().getTime());

    xhr.open("GET", "message" + query, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                render(eval(xhr.responseText));
            }

            loop(false);
        }
    };
    xhr.send();
}

// 受け取ったメッセージを表示する
function render(log) {
    var chat = document.getElementById('chat');

    chat.innerHTML = " ";
    log.reverse();

    for (var key in log) {
        var entry = log[key],
            div = document.createElement('div'),
            message = document.createTextNode(entry['name'] + ": " + entry['message']);

        div.appendChild(message);
        chat.appendChild(div);
    }
}

ほぼはじめてさわったので説明が難しいですがこれで動作します。
複数のブウラザからhttp://127.0.0.1:3000/chat.htmlにアクセスして見てください。

従来のWebアプリケーションと違い画面のリロードとか定期的にサーバへアクセスするなど余計なものがないはわかります。
がなかなか動きを把握するのにて手間取りました。

jQueryとかSocket.IOとかを使えばもっとシンプルに書けそうな気もするんですがとりあえずはこんなかんじで。



0 件のコメント:

コメントを投稿