[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. 很棒的文章,謝謝!我真要自己給nodejs試試看。比如說我要做一個nodejs網站,你知道在哪裡找得到nodejs服務器呢?

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

  3. patw

    Hi, 我剛更新了 express 3.x 部分的寫法, 測試本範例有成功喔, 請再試試看吧.

  4. patw

    手機版網頁一樣放在 Web Server 上哦!手機只是連到該頁面上瀏覽而已。

  5. 阿兵

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

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

  6. robert

    您好,我以本機run node.js,但是手機連不到本機的網頁,請問server.js 這個檔案是否有需要修改什麼設定嗎?

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *