ã€ãæè¿ã
Firefox 6ãSSE ïŒOpera 10.6 +ãChromeãWebKit 5 +ãiOS Safari 4 +ãOpera Mobile 10+ã§
æ¢ã«å©çšå¯èœïŒ ãåä¿¡ããããšãããã£ãããããã¹ãŠã®ãã©ãŠã¶ãŒã®åå以äžïŒãŠãŒã¶ãŒã«ãªãŒãããïŒã®ãµããŒãã¯ãã¯ãæå©ã§ã¯ãããŸããå±±ã ãã®æè¡ã詳ããèŠãŠã¿ãŸãããã SSEã¯7幎以äžåã«Ian Hickson
ã«ãã£ãŠæäŸãããŸãããã1幎åã«ãã©ãŠã¶ã«è¡šç€ºãããããã«ãªããŸããã WebSocketãããã®ã«ããªãå¥ã®ãããã³ã«ãå¿
èŠãªã®ã§ããïŒïŒ ãããããã¹ãŠã«é·æãšçæããããŸããSSEãäœã«åœ¹ç«ã€ãèŠãŠã¿ãŸãããã
SSEã®æŠå¿µã¯åçŽã§ããã¯ã©ã€ã¢ã³ãã¯ãµãŒããŒã€ãã³ãã«ãµãã¹ã¯ã©ã€ãããã€ãã³ããçºçãããšããã«ãã¯ã©ã€ã¢ã³ãã¯éç¥ãšãã®ã€ãã³ãã«é¢é£ããããŒã¿ãããã«åä¿¡ããŸãã SSEãããã³ã«ã®æçšæ§ãç解ããã«ã¯ãã€ãã³ããåä¿¡ããããã®éåžžã®æ¹æ³ãšæ¯èŒããå¿
èŠããããŸãããã®æ¬è³ªãç°¡åã«èª¬æããŸãã
ããŒãªã³ã°
æãåçŽã§ãããæãå¹æçãªæ¹æ³ã§ã¯ãããŸãããã¯ã©ã€ã¢ã³ãã¯æ°ç§ããšã«ã€ãã³ããæ±ããŠãµãŒããŒãããŒãªã³ã°ããŸãã äœãååšããªãå Žåã§ããã¯ã©ã€ã¢ã³ãã¯ãã¹ãŠåãããã«èŠæ±ãè¡ããŸãããäœãæ¥ããããããŸããã
é·æïŒ-ãã
-ããŒã¿ãæ¯ãããšãã§ããŸã
çæïŒ-å€ãã®è¿œå ãªã¯ãšã¹ã
-ã€ãã³ãã¯åžžã«é
ãã
-ãµãŒããŒã¯ãã¯ã©ã€ã¢ã³ããã€ãã³ããååŸããããã€ãã³ããæéåãã«ãªããŸã§ã€ãã³ããä¿åããå¿
èŠããããŸã
é·ãããŒãªã³ã°
以åã®æ¹æ³ã®æ¹è¯çã ã¯ã©ã€ã¢ã³ãã¯ãµãŒããŒã«ãªã¯ãšã¹ããéä¿¡ãããµãŒããŒã¯ããŒã¿ãå°çãããã¯ã©ã€ã¢ã³ããèªåçã«åæãããŸã§æ¥ç¶ãéãããŸãŸã«ããŸãã ããŒã¿ãå°çãããšããã«ãå¿çãéä¿¡ãããæ¥ç¶ãéãããã次ã®æ¥ç¶ãéãããŸãã
ããŒãªã³ã°ãšæ¯èŒããé·æïŒ-ãªã¯ãšã¹ãã®æå°æ°
-ã€ãã³ãã®é«ãæéç粟床
-ãµãŒããŒã¯åæ¥ç¶äžã«ã®ã¿ã€ãã³ããä¿åããŸã
ããŒãªã³ã°ãšæ¯èŒããçæïŒ-ããè€éãªã¹ããŒã
Websocket
ããã¯ãã¯ã©ã€ã¢ã³ããšãµãŒããŒãåçã®æ¡ä»¶ã§éä¿¡ã§ããããã«ãããã€ããªäºéãããã³ã«ã§ãã ãã®ãããã³ã«ã¯ãã²ãŒã ããã£ãããããã³ãªã¢ã«ã¿ã€ã ã«è¿ãéåžžã«æ£ç¢ºãªã€ãã³ããå¿
èŠãªãã¹ãŠã®ã¢ããªã±ãŒã·ã§ã³ã«äœ¿çšã§ããŸãã
ãã³ã°ããŒãªã³ã°ãšæ¯èŒããé·æïŒ-1ã€ã®æ¥ç¶ãäžæãã
-ã€ãã³ãã®éåžžã«é«ãæéç粟床
-ãã©ãŠã¶ãŒã«ãã£ãŠå¶åŸ¡ããããããã¯ãŒã¯é害管ç
ãã³ã°ããŒãªã³ã°ãšæ¯èŒããçæïŒ-HTTPã¯äºææ§ã®ãããããã³ã«ã§ã¯ãªããããç¬èªã®ãµãŒããŒãå¿
èŠã§ãããããã°ã¯è€éã§ã
ç§ãã¡ã¯ãã®ãããªçŸããWebSocketãããã³ã«ãæã£ãŠããã®ã§ããªãSSEã䜿çšããå¿
èŠããããŸããïŒïŒ ãŸãããã¹ãŠã®Webã¢ããªã±ãŒã·ã§ã³ãåæ¹åéä¿¡ãå¿
èŠãšããããã§ã¯ãããŸãã-SSEãé©ããŠããŸãã 次ã«ãSSEã¯HTTPäºæãããã³ã«ã§ãããä»»æã®WebãµãŒããŒã§ã€ãã³ããããŒããã£ã¹ããå®è£
ã§ããŸãã
ãµãŒããŒéä¿¡ã€ãã³ããããã³ã«
ã¯ã©ã€ã¢ã³ãã¯ãµãŒããŒã«èŠæ±ãéä¿¡ãããµãŒããŒã¯å¿çãšããŠæ¬¡ã®ããããŒãéä¿¡ããŸãã
Content-Type: text/event-stream
ãŸããæ¥ç¶ãéããŸããïŒphpã§ã¯ãç¡éã«ãŒããäœæã§ããŸããnode.jsã§è¡ãæ¹æ³ã«ã€ããŠã¯ããµã³ãã«èšäºã§èª¬æããŸãïŒã ããã ãã§ã-SSEã¯åäœããŸãïŒ ã¯ã©ã€ã¢ã³ãã«ããŒã¿ãéä¿¡ããããã«ããµãŒããŒã¯æ¬¡ã®åœ¢åŒã®è¡ããœã±ããã«æžã蟌ãã ãã§ãã
data: My message\n\n
è€æ°è¡ã®ããŒã¿ãéä¿¡ããå¿
èŠãããå Žåã圢åŒã¯æ¬¡ã®ããã«ãªããŸãã
data: {\n data: "msg": "hello world",\n data: "id": 12345\n data: }\n\n
ããã§ã¯ãååãšããŠããããã³ã«ããŒã¹å
šäœã§ãã ããã«ããµãŒããŒã¯ã¡ãã»ãŒãžIDãéä¿¡ã§ããŸããããã¯ãæ¥ç¶ãåæãããå Žåã«å¿
èŠã§ãã æ¥ç¶ãåæãããå Žåãã¯ã©ã€ã¢ã³ãã¯æ¥ç¶ããããšãããšãç¹å¥ãªããããŒïŒLast-Event-IDïŒãéä¿¡ããŠã倱ãããã€ãã³ãã埩å
ããŸãã
id: 12345\n data: GOOG\n data: 556\n\n
ãšã©ãŒãçºçããå Žåã®åè©Šè¡æéïŒ
retry: 10000\n data: hello world\n\n
idããã³retryãã£ãŒã«ãã¯ãªãã·ã§ã³ã§ãã
ã¯ã©ã€ã¢ã³ãã§ã¯ããã¹ãŠã次ã®ããã«ãªããŸãã
var source = new EventSource('http://localhost/stream.php'); source.addEventListener('message', function(e) {
ãã¹ãŠãéåžžã«ç°¡åã§ãã SSEãããã³ã«ã«åºã¥ããŠã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŸãããã ãã€ãã®ããã«ãããã¯ãã£ããã«ãªããŸãã
ãã«ãããŒãXMLHTTPRequest
ãã«ãããŒãã¹ããªãŒãã³ã°ãšãåŒã°ããŸãïŒFirefoxã®ã¿ããµããŒãïŒã SSEãããã³ã«ã«éåžžã«äŒŒãŠããŸãã
ããããŒã®åœ¢åŒã¯æ¬¡ã®ãšããã§ãã
Content-type: multipart/x-mixed-replace;boundary=smthing
ãããŠãããŒãã¯æ¬¡ã®åœ¢åŒã§éä¿¡ãããŸãã
Content-type: text/html\r\n\r\n --smthing\n Message\n --smthing\n
éåžžã®XHRãã¯ã©ã€ã¢ã³ãã§äœæãããŸããããªã¯ãšã¹ããéä¿¡ããåã«ãã©ã°
req.multipart = true;
èšå®ããå¿
èŠããã
req.multipart = true;
SSEã®ããã«èŠããŸããïŒ
詳现SSEã«ã€ãªããå¯èœæ§ã®ããå¥ã®ãããã³ã«ããããŸãã
XMLHTTPRequestïŒã€ã³ã¿ã©ã¯ãã£ã
ããã䜿çšããã«ã¯ããã©ãŠã¶ã¯ã³ãŒã3ïŒã€ã³ã¿ã©ã¯ãã£ãïŒã§ç¹å¥ãªreadyStateããµããŒãããå¿
èŠããããŸã-ãã®ã¹ããŒã¿ã¹ã¯ãããŒã¿ã®äžéšãå°çããããæ¥ç¶ããŸã éããããŠããªãããšã瀺ããŸãã ã³ãŒã3ã§readyStateã䜿çšããjQuery
ã«ã¯åãååã®
ãã©ã°ã€ã³ããããŸãããŸãããã€ãã®ããã«ããã¹ãŠã®ãã©ãŠã¶ãŒãã³ãŒã3ã§readyStateããµããŒãããŠããããã§ã¯ãããŸããã
äŸïŒãµãŒããŒéä¿¡ã€ãã³ãã§ã®ãã£ãã
SSEã«é¢ããäžé£ã®ã€ãã³ãïŒãªãã©ã€ã³ã«ãªãããªã³ã©ã€ã³ã«ãªããã¡ãã»ãŒãžïŒãåãå
¥ããŸãã ãªããªã SSEã¯ã¡ãã»ãŒãžãéä¿¡ã§ããªããããHTTPãä»ããŠéä¿¡ããŸãã
äœæ¥ã®ã¹ããŒã ã¯æ¬¡ã®ãšããã§ãã
-ãã£ããã«å
¥ããšããååãèŠæ±ãããŸã
-ã¯ã©ã€ã¢ã³ãã¯ãã£ãããµãŒããŒã«æ¥ç¶ããŸãã ã€ãã³ãã¹ããªãŒã ãäœæãããŸãã
-ã¯ã©ã€ã¢ã³ããæ¥ç¶ãããšããã£ããã¯å
šå¡ã«ã€ãã³ããéä¿¡ããŸãïŒïŒ
usernameïŒ
online
-ã¯ã©ã€ã¢ã³ããåæãããšããã£ããã¯å
šå¡ã«ã€ãã³ããéä¿¡ããŸãïŒïŒ
usernameïŒ
offline
-ã¯ã©ã€ã¢ã³ãã¯HTTPãPOST /ã¡ãã»ãŒãžããä»ããŠã¡ãã»ãŒãžãéä¿¡ã§ãããµãŒããŒã¯ãã®ã¡ãã»ãŒãžãåä¿¡ããSSEãä»ããŠãã¹ãŠã®ã¯ã©ã€ã¢ã³ãã«åä¿¡ããã¡ãã»ãŒãžãéä¿¡ããŸãã
ã¯ã©ã€ã¢ã³ãã³ãŒããåæããŸãããã äžéšã®ãã©ãŠã¶ã§$ .readyã®ä»£ããã«ç¡éã®ããŠã³ããŒããè¡ãããªãããã«ãsetTimeoutãå®è¡ããŸãã
setTimeout(function () {
ãŠãŒã¶ãŒåããªã¯ãšã¹ãïŒ
EventSourceãäœæããããã«ãŠãŒã¶ãŒåãæž¡ãïŒãŠãŒã¶ãŒããªã³ã©ã€ã³ã«ãªã£ãïŒãå¿
èŠãªã€ãã³ãããªãã¹ã³ããŸãã
var eventSrc = new EventSource("/event?name=" + name);
renderMessageã¡ãœãããšããŒãžã¬ã€ã¢ãŠãã¯èæ
®ããŸããã ãã¹ãŠã®ã¯ã©ã€ã¢ã³ãã³ãŒãã¯ã
index.htmlã«ãããŸãã
ãµãŒããŒåŽã«ã¯ãNode.jsããããŸãã ããã§ã¯ãã¹ãŠãããè€éã§ããã1人ã®ãŠãŒã¶ãŒãããã¹ãŠã®ãŠãŒã¶ãŒãžã®ãã«ããã£ã¹ãã¡ãã»ãŒãžã®äž»ãªé£ããã§ãããSSEãä»ããéä¿¡ã®æ§ç¯ã¯å°é£ã§ãã
å¿
èŠãªã¢ãžã¥ãŒã«ãæ¥ç¶ããŸã
var http = require('http'), fs = require('fs'), qs = require('querystring'), parse = require('url').parse;
ã«ãŒã
次ã®ãªããžã§ã¯ããå«ãã«ãŒãã«ãŒãã®ãªã¹ããäœæããŸãã
1.éååŠã ã€ã³ããã¯ã¹ããŒãžãéçããŒã¿ã®ãã«ã¡ããïŒ 'GET /': function (request, response) {
2. SSEæ¥ç¶ã®ç¢ºç«ïŒ 'GET /event': function (request, response) { var url = parse(request.url, true); var name = (url.query.name || 'anonymous').substr(0, 20); var clientId = Clients.generateClientId();
3.ã¯ã©ã€ã¢ã³ãããã®ã¡ãã»ãŒãžïŒ 'POST /message': function (request, response) { var data = '';
4.ããã©ã«ãã«ãŒã-ããŒãž404ïŒ $: function (request, response) { response.writeHead(404); response.end(); }
ã«ã¹ã¿ããŒãããŒãžã£ãŒ-ã¯ã©ã€ã¢ã³ã
æ°ããã¯ã©ã€ã¢ã³ããè¿œå ïŒè¿œå ïŒãããšããããŒãžã£ãŒã¯ã¯ã©ã€ã¢ã³ããå°çãããã¹ãŠã®ã¡ãã»ãŒãžãéä¿¡ããŸãã
add: function (clientId, response, name) { this._clients[clientId] = {response: response, name: name || 'anonymous'}; this.count++;
åé€ãããšãæ¥ç¶ãéããããã¯ã©ã€ã¢ã³ãããªãã©ã€ã³ã§ããããšãå
šå¡ã«éä¿¡ããŸãã
remove: function (clientId) {
private _sendã¡ãœããã¯ãã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããããã«äœ¿çšãããŸãã
_send: function (clients, message, name, isbot) { if (!message || !name) { return; }
_sendã¡ãœããã¯ããããªãã¯ãããŒããã£ã¹ãã¡ãœãããšãŠããã£ã¹ãã¡ãœããã䜿çšããŠããããããã¹ãŠã®ã¯ã©ã€ã¢ã³ããš1ã€ã®ã¯ã©ã€ã¢ã³ãã«ã¡ãã»ãŒãžãéä¿¡ããŸãã
ãµãŒããŒãäœæããŠãªã³ã«ããŸã
ãœãŒã¹ã³ãŒãserver.jsSSEã§ã®ãã£ããã®æºåãã§ããŸããã ãµãŒããŒãèµ·åããŸãã
$ node server.js
Firefox 6ãOpera 10.6以éãChromeãWebKit 5以éãiOS Safari 4以éãOpera Mobile 10以éã®ããããã®ãã©ãŠã¶ãŒãéããŸãã
http://
localhost/
ã«ã¢ã¯ã»ã¹ããŠãã£ããããŠãã ããïŒ
ãããã«
SSEã¯Long Polingã«åã£ãŠä»£ããåªãããã¯ãããžãŒã§ãããã·ã³ãã«ã§ãããWebSocketsã»ã©å¹æçã§ã¯ãããŸããã çŸåšãSSEã¯Opera 10.6+ïŒOpera 9ã¯å€ãSSEæšæºããµããŒãããŠããŸãïŒãChromeãSafari 5+ããµããŒãããŠããŸãã Firefoxã¯Multipart XMLHTTPRequestããµããŒãããŠããŸãããã®ããã«ã©ãããŒãäœæããSSEã€ã³ã¿ãŒãã§ãŒã¹ãšããŠäœ¿çšã§ããŸãã
åç
§è³æ
1. SSEãã£ããã®ãªã³ã©ã€ã³äŸã¯ã
sse-chat.nodester.comã§èŠãããšãã§ããŸãã
Nodesterãããã·ã®æ©èœã«ãããããã¯ãã£ããã®äžéšãåãæšãŠãããããŒãžã§ã³ã§ãïŒãªã³ã©ã€ã³ã®ãŠãŒã¶ãŒæ°ã«é¢ããã¡ãã»ãŒãžã¯ãªãããã£ããããéåºãããšããã¡ãã»ãŒãžããããŸãããé »ç¹ã«åæ¥ç¶ãããå¯èœæ§ããããŸãïŒ2.
ãœãŒã¹ã®äŸïŒ
github.com/azproduction/event-source-chat3.
å¥ã®SSEãã¥ãŒããªã¢ã«4.
ä»æ§PSãã£ããã¯habraeffectãã«ããŒããŠããããã«èŠããŸãããnodesterã§äœããããŠããããã§ãïŒå€ãã®å Žåããã®ããã«ãªããŸãïŒã çµæã«èå³ãããå Žåã¯ãGitHubãã
ãœãŒã¹ãããŠã³ããŒãããŠãã ããã
ãã«ãããŒãXMLHTTPRequestãXMLHTTPRequestã«ãã
UPDãè¿œå ãããŸããïŒ
yui_room9ãè¿œå ããŠãããã€ã³ã¿ã©ã¯ãã£ããªæè¬