1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
---
title: Using server-sent events
slug: Web/API/Server-sent_events/Using_server-sent_events
translation_of: Web/API/Server-sent_events/Using_server-sent_events
---
<p>{{DefaultAPISidebar("Server Sent Events")}}</p>
<div class="summary">
<p>É fácil desenvolver um aplicativo Web que usa <a href="/en-US/docs/Web/API/Server-sent_events">server-sent events</a>. Você precisára de um pouco de código no servidor para transmitir eventos para o front-end, mas o código do lado do cliente funciona quase de forma idêntica aos <a href="/en-US/docs/Web/API/WebSockets_API">websockets</a> em questão de tratamento de eventos recebidos. Essa é uma conexão unidirecional, portanto você não pode enviar eventos de um cliente para um servidor.</p>
</div>
<h2 id="Receiving_events_from_the_server">Receiving events from the server</h2>
<p>The server-sent event API is contained in the {{domxref("EventSource")}} interface; to open a connection to the server to begin receiving events from it, create a new <code>EventSource</code> object with the URL of a script that generates the events. For example:</p>
<pre class="brush: js notranslate">const evtSource = new EventSource("ssedemo.php");</pre>
<p>If the event generator script is hosted on a different origin, a new <code>EventSource</code> object should be created with both the URL and an options dictionary. For example, assuming the client script is on <code>example.com</code>:</p>
<pre class="brush: js notranslate">const evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true } );</pre>
<p>Once you've instantiated your event source, you can begin listening for messages from the server by attaching a handler for the {{event("message")}} event:</p>
<pre class="brush: js notranslate">evtSource.onmessage = function(event) {
const newElement = document.createElement("li");
const eventList = document.getElementById("list");
newElement.innerHTML = "message: " + event.data;
eventList.appendChild(newElement);
}
</pre>
<p>This code listens for incoming messages (that is, notices from the server that do not have an <code>event</code> field on them) and appends the message text to a list in the document's HTML.</p>
<p>You can also listen for events with <code>addEventListener()</code>:</p>
<pre class="brush: js notranslate">evtSource.addEventListener("ping", function(event) {
const newElement = document.createElement("li");
const time = JSON.parse(event.data).time;
newElement.innerHTML = "ping at " + time;
eventList.appendChild(newElement);
});
</pre>
<p>This code is similar, except that it will be called automatically whenever the server sends a message with the <code>event</code> field set to "ping"; it then parses the JSON in the <code>data</code> field and outputs that information.</p>
<div class="blockIndicator warning">
<p>When <strong>not used over HTTP/2</strong>, SSE suffers from a limitation to the maximum number of open connections, which can be specially painful when opening various tabs as the limit is <em>per browser</em> and set to a very low number (6). The issue has been marked as "Won't fix" in <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=275955" rel="noreferrer">Chrome</a> and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=906896" rel="noreferrer">Firefox</a>. This limit is per browser + domain, so that means that you can open 6 SSE connections across all of the tabs to <code>www.example1.com</code> and another 6 SSE connections to <code>www.example2.com.</code> (from <a href="https://stackoverflow.com/a/5326159/1905229">Stackoverflow</a>). When using HTTP/2, the maximum number of simultaneous <em>HTTP streams</em> is negotiated between the server and the client (defaults to 100).</p>
</div>
<h2 id="Sending_events_from_the_server">Sending events from the server</h2>
<p>The server-side script that sends events needs to respond using the MIME type <code>text/event-stream</code>. Each notification is sent as a block of text terminated by a pair of newlines. For details on the format of the event stream, see {{ anch("Event stream format") }}.</p>
<p>The {{Glossary("PHP")}} code for the example we're using here follows:</p>
<pre class="brush: php notranslate">date_default_timezone_set("America/New_York");
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
$counter = rand(1, 10);
while (true) {
// Every second, send a "ping" event.
echo "event: ping\n";
$curDate = date(DATE_ISO8601);
echo 'data: {"time": "' . $curDate . '"}';
echo "\n\n";
// Send a simple message at random intervals.
$counter--;
if (!$counter) {
echo 'data: This is a message at time ' . $curDate . "\n\n";
$counter = rand(1, 10);
}
ob_end_flush();
flush();
sleep(1);
}
</pre>
<p>The code above generates an event every second, with the event type "ping". Each event's data is a JSON object containing the ISO 8601 timestamp corresponding to the time at which the event was generated. At random intervals, a simple message (with no event type) is sent.</p>
<div class="note">
<p><strong>Note</strong>: You can find a full example that uses the code shown in this article on GitHub — see <a href="https://github.com/mdn/dom-examples/tree/master/server-sent-events">Simple SSE demo using PHP.</a></p>
</div>
<h2 id="Error_handling">Error handling</h2>
<p>When problems occur (such as a network timeout or issues pertaining to <a href="/en-US/docs/HTTP/Access_control_CORS" title="/en-US/docs/HTTP/Access_control_CORS">access control</a>), an error event is generated. You can take action on this programmatically by implementing the <code>onerror</code> callback on the <code>EventSource</code> object:</p>
<pre class="brush: js notranslate">evtSource.onerror = function(err) {
console.error("EventSource failed:", err);
};
</pre>
<h2 id="Closing_event_streams">Closing event streams</h2>
<p>By default, if the connection between the client and server closes, the connection is restarted. The connection is terminated with the <code>.close()</code> method.</p>
<pre class="notranslate">evtSource.close();</pre>
<h2 id="Event_stream_format">Event stream format</h2>
<p>The event stream is a simple stream of text data which must be encoded using <a href="/en-US/docs/Glossary/UTF-8">UTF-8</a>. Messages in the event stream are separated by a pair of newline characters. A colon as the first character of a line is in essence a comment, and is ignored.</p>
<div class="note"><strong>Note:</strong> The comment line can be used to prevent connections from timing out; a server can send a comment periodically to keep the connection alive.</div>
<p>Each message consists of one or more lines of text listing the fields for that message. Each field is represented by the field name, followed by a colon, followed by the text data for that field's value.</p>
<h3 id="Fields">Fields</h3>
<p>Each message received has some combination of the following fields, one per line:</p>
<dl>
<dt><code>event</code></dt>
<dd>A string identifying the type of event described. If this is specified, an event will be dispatched on the browser to the listener for the specified event name; the website source code should use <code>addEventListener()</code> to listen for named events. The <code>onmessage</code> handler is called if no event name is specified for a message.</dd>
<dt><code>data</code></dt>
<dd>The data field for the message. When the <code>EventSource</code> receives multiple consecutive lines that begin with <code>data:</code>, <a href="http://www.w3.org/TR/eventsource/#dispatchMessage">it will concatenate them</a>, inserting a newline character between each one. Trailing newlines are removed.</dd>
<dt><code>id</code></dt>
<dd>The event ID to set the <a href="/en/Server-sent_events/EventSource" title="en/Server-sent events/EventSource"><code>EventSource</code></a> object's last event ID value.</dd>
<dt><code>retry</code></dt>
<dd>The reconnection time to use when attempting to send the event. This must be an integer, specifying the reconnection time in milliseconds. If a non-integer value is specified, the field is ignored.</dd>
</dl>
<p>All other field names are ignored.</p>
<div class="note"><strong>Note:</strong> If a line doesn't contain a colon, the entire line is treated as the field name with an empty value string.</div>
<h3 id="Examples">Examples</h3>
<h4 id="Data-only_messages">Data-only messages</h4>
<p>In the following example, there are three messages sent. The first is just a comment, since it starts with a colon character. As mentioned previously, this can be useful as a keep-alive if messages may not be sent regularly.</p>
<p>The second message contains a data field with the value "some text". The third message contains a data field with the value "another message\nwith two lines". Note the newline special character in the value.</p>
<pre class="notranslate">: this is a test stream
data: some text
data: another message
data: with two lines
</pre>
<h4 id="Named_events">Named events</h4>
<p>This example sends some named events. Each has an event name specified by the <code>event</code> field, and a <code>data</code> field whose value is an appropriate JSON string with the data needed for the client to act on the event. The <code>data</code> field could, of course, have any string data; it doesn't have to be JSON.</p>
<pre class="notranslate">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."}
</pre>
<h4 id="Mixing_and_matching">Mixing and matching</h4>
<p>You don't have to use just unnamed messages or typed events; you can mix them together in a single event stream.</p>
<pre class="notranslate">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."}</pre>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<div>
<h3 id="EventSource"><code>EventSource</code></h3>
<div>
<p>{{Compat("api.EventSource")}}</p>
</div>
</div>
|