Baseline Widely available *
server-sent events를 ì¬ì©íë ì¹ ì í리ì¼ì´ì ì ê°ë°íë ê²ì ê°ë¨í©ëë¤. ìë² ì¸¡ììë íë¡ í¸ìëë¡ ì´ë²¤í¸ë¥¼ ì¤í¸ë¦¬ë°íë ì½ê°ì ì½ëê° íìíì§ë§, í´ë¼ì´ì¸í¸ 측 ì½ëë ë¤ì´ì¤ë ì´ë²¤í¸ë¥¼ ì²ë¦¬íë ë¶ë¶ìì ì¹ìì¼ê³¼ ê±°ì ëì¼íê² ìëí©ëë¤. ì´ë ë¨ë°©í¥ ì°ê²°ì´ê¸° ë문ì í´ë¼ì´ì¸í¸ìì ìë²ë¡ ì´ë²¤í¸ë¥¼ ë³´ë¼ ìë ììµëë¤.
ìë²ë¡ë¶í° ì´ë²¤í¸ ìì í기server-sent event APIë EventSource
ì¸í°íì´ì¤ì í¬í¨ë¼ ììµëë¤.
EventSource
ì¸ì¤í´ì¤ ìì±í기
ì´ë²¤í¸ ìì ì ììí기 ìí´ ìë²ìì ì°ê²°ì ì´ê¸° ìí´ìë ì´ë²¤í¸ë¥¼ ìì±íë ì¤í¬ë¦½í¸ì URLì ì¬ì©íì¬ ì EventSource
ê°ì²´ë¥¼ ë§ë¤ë©´ ë©ëë¤. ë¤ìì ìì ì½ëì
ëë¤.
const evtSource = new EventSource("ssedemo.php");
ì´ë²¤í¸ë¥¼ ìì±íë ì¤í¬ë¦½í¸ê° ë¤ë¥¸ ì¤ë¦¬ì§ì í¸ì¤í
ëì´ ìë¤ë©´, URLê³¼ ìµì
ëì
ë리를 모ë ì¬ì©íì¬ ìë¡ì´ EventSource
ê°ì²´ë¥¼ ë§ë¤ì´ì¼ í©ëë¤. example.com
ì í´ë¼ì´ì¸í¸ ì¤í¬ë¦½í¸ê° ìë ê²½ì°ë¥¼ ììë¡ ë¤ì´ ë³´ê² ìµëë¤.
const evtSource = new EventSource("//api.example.com/ssedemo.php", {
withCredentials: true,
});
message
ì´ë²¤í¸ ìì í기
ìë²ì ì ë³´ë¸ event
íëê° ìë ë©ìì§ë message
ì´ë²¤í¸ë¡ ìì ë©ëë¤. ë©ìì§ ì´ë²¤í¸ë¥¼ ìì í기 ìí´ìë message
ì´ë²¤í¸ë¥¼ ìí í¸ë¤ë¬ë¥¼ ì¶ê°í´ì¼ í©ëë¤.
evtSource.onmessage = function (e) {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
newElement.textContent = "message: " + e.data;
eventList.appendChild(newElement);
};
ì ì½ëë ìë²ë¡ë¶í° ì ì¡ë ë©ìì§ ì´ë²¤í¸ë¥¼ ê°ì§íê³ ë©ìì§ì í ì¤í¸ë¥¼ 문ìì HTMLì ìë 목ë¡ì ì¶ê°í©ëë¤.
ì¬ì©ì ì§ì ì´ë²¤í¸ ìì í기event
íë를 ê°ë ìë²ì ë©ìì§ë¤ì event
ì ëª
ìë ì´ë¦ì ì´ë²¤í¸ë¡ ìì ë©ëë¤. ì를 ë¤ë©´ ìëì ê°ìµëë¤.
evtSource.addEventListener("ping", function (event) {
const newElement = document.createElement("li");
const time = JSON.parse(event.data).time;
newElement.textContent = "ping at " + time;
eventList.appendChild(newElement);
});
ì´ ì½ëë ìë²ê° event
íëê° ping
ì¼ë¡ ì¤ì ë ë©ìì§ë¥¼ ë³´ë¼ ëë§ë¤ í¸ì¶ëë©°, data
íëì JSONì íì±íì¬ ê·¸ ì 보를 ì¶ë ¥í©ëë¤.
ìë²ììì ì´ë²¤í¸ ì¡ì주ì: HTTP/2 를 ì¬ì©íì§ ìì ë SSEë íì±íë ì°ê²°ì ìµë ê°ì ì íì¼ë¡ ì¸í íê³ë¥¼ 겪ì ì ìì¼ë©°, ì´ ì íì ë¸ë¼ì°ì ë¹ ì ì©ë ë¿ë§ ìëë¼ ë§¤ì° ë®ì ì(6)ë¡ ì¤ì ëì´ ìì´ í¹í ì¬ë¬ íì ì´ ë 문ì 를 겪ì ì ììµëë¤. ì´ ë¬¸ì ë Chromeê³¼ Firefoxìì ìì ëì§ ìì ê²ì¼ë¡ íìëììµëë¤. ì´ ì íì ë¸ë¼ì°ì ì ëë©ì¸ë³ë¡ ì ì©ëë¯ë¡
www.example1.com
ì ëí´ ëª¨ë íìì 6ê°ì SSE ì°ê²°ì ì´ ì ìê³ ,www.example2.com
ì ëí´ìë 6ê°ì SSE ì°ê²°ì ì´ ì ììµëë¤. (ì¶ì²: Stackoverflow). HTTP/2를 ì¬ì©í ëë ëìì ì´ ì ìë HTTP ì¤í¸ë¦¼ì ìµë ê°ìê° ìë²ì í´ë¼ì´ì¸í¸ ê°ì íìëë©°, 기본ê°ì 100ì ëë¤.
ì´ë²¤í¸ë¥¼ ë³´ë´ë ìë² ì¸¡ ì¤í¬ë¦½í¸ë MIME íì
text/event-stream
ì ì¬ì©íì¬ ìëµí´ì¼ í©ëë¤. ê° ì림ì ë ê°ì ì¤ë°ê¿ì¼ë¡ ëëë í
ì¤í¸ ë¸ë¡ì¼ë¡ ì ì¡ë©ëë¤. ì´ë²¤í¸ ì¤í¸ë¦¼ íìì ëí ìì¸í ë´ì©ì ì´ë²¤í¸ ì¤í¸ë¦¼ íìì 참조íì¸ì.
ì¬ê¸°ì ì¬ì©íê³ ìë ìì ì PHP ì½ëë ë¤ìê³¼ ê°ìµëë¤.
date_default_timezone_set("America/New_York");
header("X-Accel-Buffering: no");
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
$counter = rand(1, 10);
while (true) {
// 매 ì´ "ping" ì´ë²¤í¸ë¥¼ ì ì¡í©ëë¤.
echo "event: ping\n";
$curDate = date(DATE_ISO8601);
echo 'data: {"time": "' . $curDate . '"}';
echo "\n\n";
// 무ìì ì£¼ê¸°ë¡ ê°ë¨í ë©ìì§ë¥¼ ì ì¡í©ëë¤.
$counter--;
if (!$counter) {
echo 'data: This is a message at time ' . $curDate . "\n\n";
$counter = rand(1, 10);
}
if (ob_get_contents()) {
ob_end_flush();
}
flush();
// í´ë¼ì´ì¸í¸ê° ì°ê²°ì ì¤ë¨í ê²½ì°(íì´ì§ë¥¼ ë«ì ê²½ì°) 루í를 ì¤ë¨í©ëë¤.
if (connection_aborted()) break;
sleep(1);
}
ìì ì½ëë ë§¤ì´ "ping" ì´ë²¤í¸ íì ì ì´ë²¤í¸ë¥¼ ìì±í©ëë¤. ê° ì´ë²¤í¸ì ë°ì´í°ë ì´ë²¤í¸ê° ìì±ë ìì ì ISO 8601 íìì¤í¬í를 í¬í¨íë JSON ê°ì²´ì ëë¤. 무ìì ì£¼ê¸°ë¡ ì´ë²¤í¸ íì ì´ ìë ê°ë¨í ë©ìì§ê° ì ì¡ë©ëë¤. 루íë ì°ê²° ìíì ìê´ìì´ ê³ì ì¤íëë¯ë¡, ì°ê²°ì´ ì¢ ë£ëìëì§(ì: í´ë¼ì´ì¸í¸ê° íì´ì§ë¥¼ ë«ì ê²½ì°) íì¸íì¬ ë£¨í를 ì¤ë¨íë ì²´í¬ê° í¬í¨ëì´ ììµëë¤.
ì°¸ê³ : ì´ ê¸ì ëì¨ ì½ë를 ì¬ì©íë ì ì²´ ìì ë GitHubìì íì¸í ì ììµëë¤ â PHP를 ì¬ì©í ê°ë¨í SSE ë°ëª¨ë¥¼ 참조íì¸ì.
ìë¬ í¸ë¤ë§ë¤í¸ìí¬ íììì ëë ì ê·¼ ì ì´ì ê´ë ¨ë 문ì ë± ë¬¸ì ê° ë°ìí ë ìë¬ ì´ë²¤í¸ê° ìì±ë©ëë¤. EventSource
ê°ì²´ì onerror
ì½ë°±ì 구ííì¬ íë¡ê·¸ëë°ì ì¼ë¡ ì´ë¥¼ ì²ë¦¬í ì ììµëë¤.
evtSource.onerror = function (e) {
alert("EventSource failed.");
};
ì´ë²¤í¸ ì¤í¸ë¦¼ ë«ê¸°
기본ì ì¼ë¡ í´ë¼ì´ì¸í¸ì ìë² ê°ì ì°ê²°ì´ ë«íë©´ ì°ê²°ì´ ë¤ì ììë©ëë¤. ì°ê²°ì .close()
ë©ìëë¡ ì¢
ë£ë©ëë¤.
ì´ë²¤í¸ ì¤í¸ë¦¼ì UTF-8ì ì¬ì©íì¬ ì¸ì½ë©í´ì¼ íë ê°ë¨í í ì¤í¸ ë°ì´í°ì ì¤í¸ë¦¼ì ëë¤. ì´ë²¤í¸ ì¤í¸ë¦¼ì ë©ìì§ë ë ê°ì ê°í 문ìë¡ êµ¬ë¶ë©ëë¤. ì¤ì 첫 ë²ì§¸ 문ìê° ì½ë¡ ì´ë©´ ì¬ì¤ì 주ìì¼ë¡ ì·¨ê¸ëì´ ë¬´ìë©ëë¤.
ì°¸ê³ : 주ì ë¼ì¸ì ì°ê²°ì´ ìê° ì´ê³¼ëë ê²ì ë°©ì§í기 ìí´ ì¬ì©í ì ììµëë¤. ìë²ë ì°ê²°ì ì ì§í기 ìí´ ì£¼ê¸°ì ì¼ë¡ 주ìì ë³´ë¼ ì ììµëë¤.
ê° ë©ìì§ë í´ë¹ ë©ìì§ì íë를 ëì´íë íë ì´ìì í ì¤í¸ ë¼ì¸ì¼ë¡ 구ì±ë©ëë¤. ê° íëë íë ì´ë¦, ì½ë¡ , ê·¸ íë ê°ì í´ë¹íë í ì¤í¸ ë°ì´í°ë¡ íìë©ëë¤.
íëìì ë ê° ë©ìì§ë ë¤ìê³¼ ê°ì íë ì¤ íë를 í¬í¨íë©°, ê° íëë í ì¤ì íëì© ëì´ë©ëë¤.
event
ì´ë²¤í¸ë¥¼ ì¤ëª
íë ì´ë²¤í¸ ì íì ìë³íë 문ìì´ì
ëë¤. ì´ ê°ì´ ì§ì ëì´ ìë¤ë©´ ë¸ë¼ì°ì ë ì§ì ë ì´ë²¤í¸ ì´ë¦ì ëí 리ì¤ëìê² ì´ë²¤í¸ë¥¼ ë°ììíµëë¤. ì¹ ì¬ì´í¸ ìì¤ ì½ëê° ì´ë¦ì ê°ë ì´ë²¤í¸ë¥¼ ìì í기 ìí´ìë addEventListener()
를 ì¬ì©í´ì¼ í©ëë¤. ë©ìì§ì ì´ë²¤í¸ ì´ë¦ì´ ì§ì ëì§ ìì ê²½ì° onmessage
í¸ë¤ë¬ê° í¸ì¶ë©ëë¤.
data
ë©ìì§ì ë°ì´í° íëì
ëë¤. EventSource
ê° data:
ë¡ ììíë ì°ìë ì¬ë¬ ì¤ì ë°ê² ëë©´ ì´ë¥¼ ì°ê²°íì¬ ê° ì¤ ì¬ì´ì ê°í 문ì를 ì½ì
í©ëë¤. ëì ìë ê°í 문ìë ì ê±°ë©ëë¤.
id
EventSource
ê°ì²´ì ë§ì§ë§ ì´ë²¤í¸ ID ê°ì ì¤ì íë ì´ë²¤í¸ IDì
ëë¤.
retry
ì¬ì°ê²° ìê°ì ëë¤. ìë²ìì ì°ê²°ì´ ëì´ì§ë©´ ë¸ë¼ì°ì ë ì¬ì°ê²°ì ìëí기 ì ì ì§ì ë ìê°ì 기ë¤ë¦½ëë¤. ì´ ê°ì ë°ë¦¬ì´ ë¨ìì ì ìì¬ì¼ í©ëë¤. ì ìê° ìë ê°ì´ ì§ì ë ê²½ì° ì´ íëë 무ìë©ëë¤.
ì´ë¥¼ ì ì¸í 모ë íë ì´ë¦ì 무ìë©ëë¤.
ì°¸ê³ : ì½ë¡ ì í¬í¨íì§ ìë ì¤ì ê²½ì° ì ì²´ ì¤ì´ ë¹ ê° ë¬¸ìì´ê³¼ í¨ê» íë ì´ë¦ì¼ë¡ ì²ë¦¬ë©ëë¤.
ìì ë°ì´í°ë§ ìë ë©ìì§ë¤ì ìì ììë ì¸ ê°ì ë©ìì§ê° ì ì¡ë©ëë¤. 첫 ë²ì§¸ë ì½ë¡ 문ìë¡ ììí기 ë문ì 주ìì¼ë¡ ê°ì£¼ë©ëë¤. ìì ì¸ê¸í ëë¡ ì´ë keep-alive ë©ì»¤ëì¦ì¼ë¡ ë©ìì§ê° ì 기ì ì¼ë¡ ì ì¡ëì§ ìì ì ìì ë ì ì©í ì ììµëë¤.
ë ë²ì§¸ ë©ìì§ìë ê°ì´ "some text" ì¸ ë°ì´í° íëê° í¬í¨ëì´ ììµëë¤. ì¸ ë²ì§¸ ë©ìì§ìë ê°ì´ "another message\nwith two lines" ì¸ ë°ì´í° íëê° í¬í¨ëì´ ììµëë¤. ê°í í¹ì 문ìê° ê°ì í¬í¨ëì´ ììì ì ìíì¸ì.
: this is a test stream
data: some text
data: another message
data: with two lines
ì´ë¦ì´ ìë ì´ë²¤í¸
ì´ ìì ë ì´ë¦ì´ ì§ì ë ì´ë²¤í¸ë¥¼ ë³´ë
ëë¤. ê° ì´ë²¤í¸ë event
íëì ëª
ìë ì´ë²¤í¸ ì´ë¦ê³¼ í´ë¼ì´ì¸í¸ê° ì´ë²¤í¸ì ëí ìì
ì ìíí기 ìí´ íìí ë°ì´í°ë¥¼ í¬í¨í ì ì í JSON 문ìì´ ê°ì ê°ì§ data
íë를 ê°ì§ê³ ììµëë¤. ë¬¼ë¡ data
íëìë JSONì´ ìëëë¼ë 모ë 문ìì´ ë°ì´í°ë¥¼ ê°ì§ ì ììµëë¤.
event: userconnect
data: {"username": "bobby", "time": "02:33:48"}
event: usermessage
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}
event: userdisconnect
data: {"username": "bobby", "time": "02:34:23"}
event: usermessage
data: {"username": "sean", "time": "02:34:36", "text": "Bye, bobby."}
í¼í©í
ì´ë¦ì´ ìë ë©ìì§ë íì ì´ ìë ì´ë²¤í¸ë§ ì¬ì©í íìë ììµëë¤. íëì ì´ë²¤í¸ ì¤í¸ë¦¼ìì ì´ë¥¼ í¼í©íì¬ ì¬ì©í ì ììµëë¤.
event: userconnect
data: {"username": "bobby", "time": "02:33:48"}
data: Here's a system message of some kind that will get used
data: to accomplish some task.
event: usermessage
data: {"username": "bobby", "time": "02:34:11", "text": "Hi everyone."}
ë¸ë¼ì°ì í¸íì±
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4