php 通知客户端,PHP+SSE服务器向客户端推送消息
SSE與WebSocket作用相似,都是建立瀏覽器與服務(wù)器之間的通信渠道,然后服務(wù)器向?yàn)g覽器推送信息。 但是WebSocket比SSE強(qiáng)大很多,SSE只能作為一個(gè)輕量級(jí)的消息推送方案,解決了從服務(wù)端向客戶端單向推送消息的場(chǎng)景,而Websocket是全雙工通道,可以雙向通信。 SSE應(yīng)用場(chǎng)景可以是微博更新、股價(jià)更新、消息通知、賽事結(jié)果等。
目前主流瀏覽器都支持SSE,但是IE系除外。
客戶端代碼
先來看客戶端代碼,新建一個(gè)html頁面文件,在script部分添加以下代碼:
if(typeof(EventSource) !== "undefined") {
let source = new EventSource("sse.php");
source.onmessage = (e) => {
if (e.data == 'null') {
return false;
} else {
let edata = JSON.parse(e.data);
$('#result').append(edata.id + ':' + edata.message + "
");
}
};
} else {
alert('您的瀏覽器不支持SSE');
}
首先,使用typeof(EventSource)來判斷瀏覽器對(duì)SSE的支持情況。
接著創(chuàng)建一個(gè)新的EventSource對(duì)象,然后定義發(fā)送更新的服務(wù)端的 URL(本例中是 "sse.php"),如果是跨域的請(qǐng)求,需要這樣設(shè)置:let source = new EventSource("http://xxx.com/sse.php", { withCredentials: true });,并需要服務(wù)端代碼開啟允許跨域。
每接收到一次更新,就會(huì)發(fā)生 onmessage 事件。
當(dāng) onmessage 事件發(fā)生時(shí),把已接收的數(shù)據(jù)推入 id 為 #result 的元素中。
EventSource 對(duì)象支持3種事件:
onopen:當(dāng)通往服務(wù)器的連接被打開時(shí)觸發(fā)。
onmessage:當(dāng)接收到消息時(shí)觸發(fā)。
onerror:當(dāng)發(fā)生錯(cuò)誤時(shí)觸發(fā)。
出于安全,我們可以在onmessage事件中檢測(cè)消息的來源域:
source.onmessage = (e) => {
if (e.origin != 'https://www.helloweba.net') {
alert('消息來源不屬于https://www.helloweba.net');
return;
}
...
}
服務(wù)端代碼
我們使用PHP來寫一個(gè)服務(wù)端發(fā)送數(shù)據(jù)的例子,當(dāng)然你也可以使用Java/Python等任意服務(wù)端語言實(shí)現(xiàn)。
服務(wù)器端事件流的語法是非常簡(jiǎn)單的。把 "Content-Type" 報(bào)頭設(shè)置為 "text/event-stream"。現(xiàn)在,就可以開始發(fā)送事件流了。
header('X-Accel-Buffering: no');
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
ob_end_clean();
ob_implicit_flush(1);
while(1){
$data = [
"id" => time(),
"message" => '歡迎來到helloweba,現(xiàn)在是北京時(shí)間'.date('Y-m-d H:i:s')
];
returnEventData($data);
sleep(10);
}
function returnEventData($returnData, $event='message', $id=0, $retry=0){
$str = '';
if($id>0){
$str .= "id: {$id}".PHP_EOL;
}
if($event){
$str.= "event: {$event}".PHP_EOL;
}
if($retry>0){
$str .= "retry: {$retry}".PHP_EOL;
}
if(is_array($returnData)){
$returnData = json_encode($returnData);
}
$str .= "data: {$returnData}".PHP_EOL;
$str .= PHP_EOL;
echo $str;
}
以上代碼流程大致為:
1.把報(bào)頭 "Content-Type" 設(shè)置為 "text/event-stream";
2.規(guī)定不對(duì)頁面進(jìn)行緩存;
3.輸出發(fā)送數(shù)據(jù);
4.向客戶端刷新輸出數(shù)據(jù)。
注意:每一次發(fā)送的信息,由若干個(gè)message組成,每個(gè)message內(nèi)部由若干行組成,每一行都是如下格式。
[field]: value\n
其中[field]有四個(gè)值,分別是:
id:數(shù)據(jù)標(biāo)識(shí)符用id字段表示,相當(dāng)于每一條數(shù)據(jù)的編號(hào)。
event:表示自定義的事件類型,默認(rèn)是message事件。瀏覽器可以用addEventListener()監(jiān)聽該事件。
retry:指定瀏覽器重新發(fā)起連接的時(shí)間間隔。當(dāng)時(shí)間間隔到期會(huì)重連,另外一個(gè)是由于網(wǎng)絡(luò)錯(cuò)誤等原因,導(dǎo)致連接出錯(cuò)時(shí)也會(huì)重連。
data:數(shù)據(jù)內(nèi)容,如果數(shù)據(jù)很長,可以分成多行,最后一行用\n\n結(jié)尾,前面行都用\n結(jié)尾。
完整的消息內(nèi)容格式:
id: msg1\n
event: foo\n
retry: 10000\n
data: some text\n
data: another message\n
data: with two lines \n\n
上述代碼中,我們?cè)O(shè)置了每隔10秒鐘向客戶端輸出一條數(shù)據(jù),實(shí)際應(yīng)用中服務(wù)端有個(gè)任務(wù)當(dāng)發(fā)現(xiàn)新的數(shù)據(jù)時(shí)就觸發(fā)輸出流事件。
總結(jié)
以上是生活随笔為你收集整理的php 通知客户端,PHP+SSE服务器向客户端推送消息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java synchronized关键字
- 下一篇: 动态规划算法php,php算法学习之动态