用於服務器實時向客戶端推送消息,這個是單向推送server to clientphp
服務器端html
header頭git
要想服務器端推送:在服務器端的報頭要定義:
header('Content-Type:text/event-stream'),服務器發送的響應內容應該使用這種`text/event-stream`的MIME;這樣客戶端才能理解你這是發送的不是普通的數據, eventsource對象才能識別github
事件流正則表達式
服務器端發送事件流(內容);
每執行一次php文件就產生一個事件流;
事件流是由多個消息組成;
消息是一個後面都有一個空行做爲分隔符
一個消息就是一個事件
一個消息能夠由一個或者多個字段組成
字段是由字段名,冒號,字段值(數據),`字段名:值`;
產生一個空行(即兩個換行符)表明一個事件(消息)的結束
在一個文件中定義多個未命名事件,後面的會覆蓋前面的,
消息中的多個字段用一個`\n`(換行符)分隔
一個消息的結束用`\n\n`(產生一個空行);
一個字段的開始必須是以`data:`開頭,例如`data:hello world!\n`,客戶端會接受到`hello world!`,
編碼形式只能是使用utf-8,不能本身指定
說的也是雲裏霧裏,其實你只要知道我要用這種特定的格式來發送數據就行,直接下面的代碼解釋json
服務器代碼數組
我就解說下面三個消息,解釋完了也就明白了,
1. 開始:報頭,這個是必須的,就是要告訴客戶端,你要把個人數據放在eventSource對象中;
2. 第一個消息:第一個字段是打印一個時間,第二個字段打印一個‘nihao’,第三個字段打印‘hehe’,第四個字段打印‘nihaoo’,第五個字段打印‘bbbb’;最後兩個\n\n表明消息的結束
注意:每一個字段後面是有一個\n,來告訴瀏覽器我這是一個字段,而兩個\n\n,是告訴瀏覽器我這個消息結束了。每一個字段的開頭必須是:data:,這個一個沒有事件名的消息
3. 第二個事件是有事件名,有名字的事件是使用event:開頭,值是事件名,這第二個消息就是定義了一個名字爲hello的事件。
4. 第三個消息:差異就是此次發送的是一個json瀏覽器
//服務器代碼 <?php header('Content-Type:text/event-stream'); // header("Cache-Control:no-cache");//有的瀏覽器會緩存,若是默認是緩存的話就加上這句 date_default_timezone_set('Asia/Shanghai'); //第一個消息 while(1) { echo 'data:'.date('Y-m-d H:i:s')."\n"; echo "data: nihao\ndata: hehe\n"; echo "data: nihaoo\n"; echo 'data: bbbb'; echo "\n\n"; //第二個消息 echo "event: hello\n"; echo "data: world\n\n"; //第三個消息 echo "event:hh\n"; echo 'data: {"time":"aaaa"}'."\n"; echo "\n\n"; flush(); sleep(1); } ?>
客戶端
EventSource
這個API,要使用它,必須先實例化,而且必須給他傳遞一個參數,這個參數就是請求服務器的地址
`var ES = new EventSource('服務器地址')`;
監聽
EventSource對象屬性和方法
屬性
error
message
open
readyState
url緩存
方法
close()服務器
- 當鏈接發生錯誤的時候觸發error事件
- 當成功鏈接時觸發open事件
- 當接收到沒有命名的事件時觸發message事件
- readyState返回當前狀態
- 0 =>正在創建鏈接
- 1 =>鏈接處於打開狀態,正在調度事件
- 2 =>沒有創建鏈接
- url返回頁面地址
- close(),關閉鏈接
當成功鏈接後它會一直處於監聽狀態,監聽服務器發送來的信息,若是斷開了鏈接,客戶端會自動從新進行鏈接,除非你用close關閉。
命名事件
命名事件的接收要用addEventListener來監聽,用法就像我下面代碼寫的
未命名事件
用DOM0級的方法或者是DOM2級的方法都行
`ES.onmessage = function(e){}`
`ES.addEventListener('message',function(e){});`
解析
JSON
若是接收的是json,則要先解析`JSON.parse(e.data)`;
多字段
對於多個字段的,若是向要解析出來每一個字段來,就要使用正則表達式,因爲瀏覽器會把整個消息變成一個字符串,並在每一個字段後面添加一個換行符,而String類型有一個split方法,只須要用換行符做分隔,因此只須要`e.data.split(/\s/)`,這就返回一個數組,數組的每一項就是一個字讀的值
//客戶端代碼 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>服務器推送</title> </head> <body> <div id="box"></div> <div id="box2"></div> <div id="box3"></div> <script> var evtSource = new EventSource('server.php'); var box = document.getElementById("box"); var box2 = document.getElementById('box2'); var box3 = document.getElementById('box3'); // evtSource.onerror = function(e) { console.log('error'); } evtSource.onopen = function(e) { console.log("open"); } evtSource.onmessage = function (e) { //2015-06-12 22:09:04 nihao hehe nihaoo bbbb box.innerHTML = e.data; //["2015-06-12", "22:08:55", "nihao", "hehe", "nihaoo", "bbbb"] console.log(e.data.split(/\s/)); //http://127.0.0.1/server.php console.log(evtSource.url) } evtSource.addEventListener('hello',function(e) { //world box2.innerHTML = e.data; }); evtSource.addEventListener('hh',function(evt) { //aaaa box3.innerHTML = JSON.parse(evt.data).time; }); </script> </body> </html>
問題
在使用的過程當中可能會遇到php進行了緩存,這樣的會致使,客戶端數據不能及時的更新,你須要在php.ini中禁止掉緩存 `output_buffering = On`這項你禁止掉,而且在php文件中`flush()`;
好久沒有在博客園寫文章了,老是感受要寫出有點質量的文章才能拿出來,至少是本身認爲的,可是寫有點質量的文章,老是感受本身水平不行。有時想記錄學習筆記,因而我就在github上弄了一個靜態網站,這裏我會記錄個人學習和複習過程,一些小的東西我也會記錄的。地址:www.evil007.com。名字很嚇人,就是爲了霸氣了。嘿嘿。
參考:
w3c:eventsource:http://www.w3.org/TR/eventsource/
MDN:https://developer.mozilla.org/zh-CN/docs/Server-sent_events/EventSource