一面微信墻的誕生(4) 消息推送的實(shí)現(xiàn)

上一節(jié):一面微信墻的誕生(3) 用戶端界面的創(chuàng)建

在本系統(tǒng)中,消息的推送使用了 Server-Send Event 技術(shù)鸠珠,這是一種 HTTP 長(zhǎng)輪詢協(xié)議遗淳,可視作連接建立后,服務(wù)器將數(shù)據(jù)主動(dòng)推送給客戶端令哟,HTML5已經(jīng)有了支持這一技術(shù)的API恼琼。

推送服務(wù)

我設(shè)計(jì)的推送服務(wù)是這樣的,服務(wù)器每3秒從數(shù)據(jù)庫(kù)拉取新的留言信息屏富,并推送給服務(wù)器晴竞。如果沒(méi)有新的留言,則進(jìn)入下一個(gè)3秒的等待狠半。

在 server 文件夾新建 push.php

<?php
/**
 * PHP默認(rèn)執(zhí)行時(shí)間為30秒
 * 超過(guò)30秒就會(huì)停止運(yùn)行
 * 所以將執(zhí)行時(shí)間設(shè)為0噩死,也就是不限制
 * 才能長(zhǎng)時(shí)間地進(jìn)行推送服務(wù)
 */
set_time_limit(0);
/**
 * 允許所有域監(jiān)聽(tīng)本服務(wù)發(fā)出的消息
 * 上傳到公網(wǎng)后應(yīng)將其改成內(nèi)部服務(wù)器的域名
 */
header('Access-Control-Allow-Origin: *');

//將文件類型定義為 event-stream
header('Content-Type: text/event-stream');

//關(guān)閉緩存
header('Cache-Control: no-cache');

//創(chuàng)建數(shù)據(jù)庫(kù)實(shí)例
require('../util/database.class.php');
$db=Db::getInstance();

/**
 * 時(shí)間節(jié)點(diǎn)
 * 記錄每一次推送的時(shí)間點(diǎn)
 * 加載時(shí)初始化為當(dāng)前時(shí)間
 */
$time=time();

while(true){
    /**
     * 只查詢比時(shí)間結(jié)點(diǎn)更晚的消息,即還沒(méi)有推送過(guò)的消息
     * 順帶把留言者的消息一起查詢出來(lái)
     */
    $messages=$db->select("SELECT * FROM message m  JOIN user u ON m.openid=u.openid WHERE m.posttime>=$time");

    //如果有消息神年,推送給客戶端
    if(!empty($messages)){
        //更新時(shí)間結(jié)點(diǎn)
        $time=time();
        /**
         * 打包為json
     * PHP_EOL表示換行符已维,在linux服務(wù)器中等價(jià)于 /n
     */
        echo "data: ". json_encode($messages) . PHP_EOL;
        //輸出空行表示推送數(shù)據(jù)結(jié)束
        echo PHP_EOL;
        //釋放數(shù)據(jù)緩沖區(qū)
        ob_flush();
        //推送到瀏覽器
        flush();
    }
    //暫停3秒
    sleep(3);
}

為方便觀察六孵,先將查詢語(yǔ)句中的 where 條件去掉励幼,在瀏覽器中打開(kāi) push.php恩沽,觀察到服務(wù)器每3秒會(huì)把所有的數(shù)據(jù)輸出來(lái)一次蚤吹。關(guān)閉 push.php 逛艰,將查詢條件恢復(fù)染坯。


圖4-1 push.php在瀏覽器的表現(xiàn)

制作“墻面”

在 display 文件夾建立 index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>微信墻</title>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
    <style>
    /* 使用css 對(duì)消息進(jìn)行簡(jiǎn)單布局 */
    #main{
        width:100%;
    }
    .message{
        display:flex;
        padding:20px 0;
        width:100%;
        font-size:40px;
        border-bottom:dashed 1px #666;
    }
    .message>.avatar{
        width:140px;
    }
    .message>.avatar>img{
        width:120px;
        height:120px;
        border-radius:50%;
    }
    .message>.content{
        flex-grow:1;
    }
    </style>
</head>
<body>
    <div id="main">
    </div>
</body>
<script>
    $(document).ready(function(){
        //建立監(jiān)聽(tīng)
        var source=new EventSource('../server/push.php');

        //服務(wù)器消息發(fā)來(lái)時(shí)筒扒,將消息整理好添加到 #main 中
        source.onmessage=function(msg){
            var data=JSON.parse(msg.data);
            //判斷解析后數(shù)據(jù)是不是數(shù)組
            if(data.constructor.toString().indexOf('Array')>0)
                data.forEach(function(message){
                    addMsg(message);
                });
        }
    });

    function addMsg(message){
        var newElement=$('<div></div>')
        .addClass('message')
        .html(`
                <div class="avatar"><img src="${message.avatarUrl}"></div>
                <div class="content"><p>${message.nickname}: ${message.content}</p></div>
        `);
        $('#main').append(newElement);

        //讓滾動(dòng)條是始終在最下方
        $(document).scrollTop(document.body.scrollHeight);
    }
</script>
</html>

同時(shí)打開(kāi) localhost/wall/display 和 localhost/wall/client
在用戶端界面下發(fā)送一條留言


圖4-2 在用戶端發(fā)送消息
圖4-3 “墻端”成功收到消息

至此忘苛,我們已經(jīng)完成了一個(gè)微信墻的功能部分护奈,最后我們要做的就是把它接入到微信開(kāi)放平臺(tái)中:


圖4-4 已經(jīng)完成的部分

下一節(jié):一面微信墻的誕生(5) 接入微信開(kāi)放平臺(tái)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缔莲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子霉旗,更是在濱河造成了極大的恐慌痴奏,老刑警劉巖磺箕,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異抛虫,居然都是意外死亡松靡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門建椰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)雕欺,“玉大人,你說(shuō)我怎么就攤上這事棉姐⊥懒校” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵伞矩,是天一觀的道長(zhǎng)笛洛。 經(jīng)常有香客問(wèn)我,道長(zhǎng)乃坤,這世上最難降的妖魔是什么苛让? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮湿诊,結(jié)果婚禮上狱杰,老公的妹妹穿的比我還像新娘。我一直安慰自己厅须,他們只是感情好仿畸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著朗和,像睡著了一般错沽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上眶拉,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天千埃,我揣著相機(jī)與錄音,去河邊找鬼镀层。 笑死镰禾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唱逢。 我是一名探鬼主播吴侦,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坞古!你這毒婦竟也來(lái)了备韧?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤痪枫,失蹤者是張志新(化名)和其女友劉穎织堂,沒(méi)想到半個(gè)月后叠艳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡易阳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年附较,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潦俺。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拒课,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出事示,到底是詐尸還是另有隱情早像,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布肖爵,位于F島的核電站卢鹦,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏劝堪。R本人自食惡果不足惜冀自,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望幅聘。 院中可真熱鬧凡纳,春花似錦、人聲如沸帝蒿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)葛超。三九已至,卻和暖如春延塑,著一層夾襖步出監(jiān)牢的瞬間绣张,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工关带, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留侥涵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓宋雏,卻偏偏與公主長(zhǎng)得像芜飘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子磨总,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容