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