[Node.js] 使用 Node.js 來達成電腦網頁與手機網頁即時互動

Standard

這幾年 Node.js 在台灣許多網站都開始使用,我對這項技術一直頗有興趣,在想能怎麼使用這項技術去玩些有趣的互動。

曾照著網上熱心前輩所寫的文章試著寫寫看,也在去年九月參加了 HTML5與Node.js在台灣聯合技術小聚,但一時案子忙碌,實在沒有心力好好研究便停滯了。

最近公司上線的案子(1, 2)剛好能有這個機會讓我來玩玩,目的是讓使用者透過手機網頁來與電腦開啟的網頁做些即時互動。
用 App 寫要考量跨平台與門檻(還要去下載 App,應該會讓一些單純想玩玩 Event 的使用者卻步)的問題,因此便希望能都用 Web 上的技術來達成囉。

此篇便簡單紀錄一下 Node.js 在 FreeBSD 上的安裝,以及簡單製作一個手機與電腦即時互動的網頁。

自認觀念上還不是相當清楚便迫不及待分享了,若有誤之處還請前輩給予指導囉 :)

一、安裝

2013/05/13 更新:

近日有網友問到新版的寫法不同,照舊寫法會不通,於是我再更新版本試了,請參考看看囉。

我自家使用的伺服器環境是 FreeBSD,所以這邊就介紹在 FreeBSD 上安裝 Nodejs 的方法。
ports 裡面有喔!直接進去裝就可以了~真是方便!

root@patwbsd [/root] # cd /usr/ports/www/npm/
root@patwbsd [/usr/ports/www/npm] # make install clean

這邊會出現藍底畫面,請選擇勾選安裝 node-devel。

如果順利的話應該就可以安裝完畢,但有時候會遇到找不到相符版本的情況,那就這樣做吧:

# 看起來 work 裡面沒有最新版 v0.6.14 ... 好吧,自己去抓回來。
root@patwbsd [/usr/ports/www/node/work] # fetch http://nodejs.org/dist/v0.6.14/node-v0.6.14.tar.gz
node-v0.6.14.tar.gz     100% of 10MB 1838 kBps

# 解壓縮:
root@patwbsd [/usr/ports/www/node/work] # tar zxf node-v0.6.14.tar.gz

# 然後進去編譯:
root@patwbsd [/usr/ports/www/node/work] # cd node-v0.6.14
root@patwbsd [/usr/ports/www/node/work/node-v0.6.14] # ./configure
root@patwbsd [/usr/ports/www/node/work/node-v0.6.14] # gmake

# 再出來安裝:
root@patwbsd [/usr/ports/www/node/work] # cd ..
root@patwbsd [/usr/ports/www/node] # make install clean

經過一段時間的等待,終於安裝完了!

可以試一下能不能執行,印出 nodejs 的版本試試:
※小提醒:如果 FreeBSD 還沒認出 node,就 rehash 一下再執行。

root@patwbsd [/root ] # node -v
v0.10.4

安裝介紹至此終了。
接下來是第二單元,來實作囉!:D


二、實作:使用 Node.js 來達成電腦網頁與手機網頁即時互動

這邊會寫一個簡單的範例來展示怎麼用 Node.js 來達成電腦網頁與手機網頁即時互動。

首先,我們會用上 socket.io 跟 express 兩個套件,先裝好吧:

root@patwbsd [/home/ftp/patw/nodejs] # npm install socket.io
root@patwbsd [/home/ftp/patw/nodejs] # npm install express

裝完之後,應該可以在所在目錄底下看到 node_modules/ 目錄。

OK,準備完畢,開始寫吧。
我們可以將這隻 nodejs 程式命名為 server.js,先簡單寫些內容測試看看:

express 2.x 版本寫法:

// 引入 express & socket.io
var app = require('express').createServer()
var io = require('socket.io').listen(app);

// 偵聽在 8081 port,隨你喜歡
app.listen(8081);
console.log('Server running');

// Routing,其實這首頁沒什麼用
app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

express 3.x 版本寫法,請將前面改成:

var express = require('express'),
    app = express(),
    http = require('http'),
    server = http.createServer(app),
    io = require('socket.io').listen(server);

server.listen(8081);

存檔,再準備一個預設的 index.html 用來看看 Server 是否有 Run 起來吧。(照慣例打個 Hello world! 好了 :D)

Run run 看:

root@patwbsd [/home/ftp/patw/nodejs] # node server.js
   info  - socket.io started
Server running

順利的話應該可以看到執行後的兩行訊息,其中 Server running 是我們在程式中用 console.log 印出的。
然後連線到 http://你的ip:8081/ ,應該就可以看到剛剛我們所設定的 index.html 內容。

接著,我們要增加偵聽事件,讓 Nodejs Server 在接收到訊息後再發出動作,以達到互動的效果。
一樣是改 server.js 這支:

express 2.x 版本寫法:

var app = require('express').createServer()
var io = require('socket.io').listen(app);

app.listen(8081);
console.log('Server running');

app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

// 連線
io.sockets.on('connection', function (socket) {

    // 偵聽 send 事件
    socket.on('send', function (data) {

        // 然後我們依據 data.act 做不同的動作
        switch ( data.act )
        {
            // 這個是使用者打開手機網頁後發生的事件
            case 'enter':
            io.sockets.emit('get_response', data);
            console.log('Sending getEnter');
            break;

            // 這個是使用者在手機網頁中點擊按鈕,讓電腦網頁背景變色的事件
            case 'changebg';:
            io.sockets.emit('get_response', data);
            console.log('Sending changeBg');
            break;
        }

    });

});

express 3.x 版本寫法,請將前面改成:

var express = require('express'),
    app = express(),
    http = require('http'),
    server = http.createServer(app),
    io = require('socket.io').listen(server);

server.listen(8081);

OK,存檔。一樣用 node server.js 讓它運行。

伺服器端的程式差不多了,再來是電腦網頁與手機網頁的撰寫囉。
要怎麼讓特定手機網頁能夠控制特定電腦網頁呢?思考方向是──設定一組專屬的 KEY,一對一,就可以知道只聽到某個 KEY 的手機網頁呼叫,電腦網頁才會動作。

為了讓手機使用者方便輸入,這邊將網址包含 KEY 變成一組 QRCode。 (使用 Google Charts)

流程大致是這樣:

使用者開啟電腦網頁→用手機掃描網頁上的 QRCode→手機打開了專屬 KEY 的網頁→電腦網頁透過 Nodejs 伺服器知道這個 KEY 被打開了→開始互動

電腦網頁的 code 如下:

<!document html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Nodejs - 電腦網頁</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script src="http://Nodejs伺服器位置:埠號/socket.io/socket.io.js" type="text/javascript"></script>
        <style type="text/css">
            #main {
                display: none;
            }
        </style>
        <script type="text/javascript">
            // 用來產生類似 GUID 的字串
            function S4() {
               return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
            }

            function NewGuid() {
               return (S4()+S4());
            }

            $(document).ready(function(){

                var key = NewGuid();
                console.log(key);
                $("#qrcode").append("<img src='http://chart.apis.google.com/chart?chs=300x300&cht=qr&chl=http://手機版網址/?key=" + key + "&choe=UTF-8' />");

                // NodeJS Server
                var nodejs_server = "Nodejs伺服器位置:埠號";

                // 進行 connect
                var socket = io.connect("http://" + nodejs_server);

                // 偵聽 nodejs 事件
                socket.on("get_response", function (b) {

                    var combine = b.key + "_" + b.act;
                    console.log(combine);

                    switch (combine) {

                        // 當擁有特定 KEY 的使用者打開手機版網頁,觸發 enter 事件,就會將 qrcode 隱藏,並秀出一張圖
                        case key + "_enter":
                            setTimeout(function () {

                                $("#qrcode").hide();
                                $("#main").show();

                            }, 500);
                            break;

                        // 當擁有特定 KEY 的使用者在手機版網頁中,觸發 changebg 事件,就會將網頁的背景顏色隨機變換
                        case key + "_changebg":
                            setTimeout(function () {

                                var str = "0123456789abcdef", t = "";
                                for (j = 0; j < 6; j++) {
                                    t = t + str.charAt(Math.random() * str.length);
                                }

                                $("body").css("background-color", t);

                            }, 500);
                            break;

                    }
                });

            });
        </script>
    </head>
<body>

        <div id="qrcode"></div>
        <div id="main"><img src="amber.jpg" /></div>

</body>
</html>

至於手機版網頁的 code 如下:(本例用 PHP 撰寫,目的是取得 querystring 的 key 值)

<!DOCTYPE html>

<html>
<head>
    <meta charset="UTF-8" />
    <title>Nodejs -  手機網頁</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
        <meta name="author" content="patw, Patrick Wang" />
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
    <script src="http://Nodejs伺服器位置:埠號/socket.io/socket.io.js" type="text/javascript"></script>
    <script type="text/javascript">
    $(document).ready(function() {

        // ==========================================================================================================================
        // 建立 Socket IO 連線
        // ==========================================================================================================================
        var socket = io.connect("http://Nodejs伺服器位置:埠號");
        "undefined" != typeof console && console.log("user enter via mobile");
        // ==========================================================================================================================

        "undefined" != typeof console && console.log("enter mobile page");
        socket.emit("send", {
            key: "<?php echo $_GET['key'];?>",
            act: "enter"
        });

        $("#change_btn").click(function(){
            "undefined" != typeof console && console.log("send change color command");
            socket.emit("send", {
                key: "<?php echo $_GET['key'];?>",
                act: "changebg"
            });
        });

    });
    </script>
</head>
<body>

<p>打開手機網頁成功!快看看你的電腦螢幕吧!</p>

<input id="change_btn" type="button" value="控制電腦端變背景色" />

</body>
</html>

最後放個成果的 DEMO 影片:

以上,與大家分享。
也希望有心得的朋友一起討論喔:D 看能做出什麼更有趣的東西

21 thoughts on “[Node.js] 使用 Node.js 來達成電腦網頁與手機網頁即時互動

  1. hello 你好
    我有試著照您的程式碼做可是弄不出來目前新的express3.x與socket.io寫法有些不同,我目前的問題在我的圖片顯示不出來,以及手機show出網頁後電腦端沒動作。
    不知是哪裡有問題可以幫忙一下嗎?

  2. 阿兵

    你好
    最近在學習Node.js
    很喜歡你的範例拿來練習
    現在卡在手機無法連上
    DNS查詢失敗

    一直不知道改哪裡好
    因此想請教你
    謝謝

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *