上一節(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ù)染坯。
制作“墻面”
在 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ā)送一條留言
至此忘苛,我們已經(jīng)完成了一個(gè)微信墻的功能部分护奈,最后我們要做的就是把它接入到微信開(kāi)放平臺(tái)中:
下一節(jié):一面微信墻的誕生(5) 接入微信開(kāi)放平臺(tái)