-
Notifications
You must be signed in to change notification settings - Fork 22
/
index.html
432 lines (430 loc) · 20.1 KB
/
index.html
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
<!DOCTYPE html>
<html>
<head>
<title>Beacon</title>
<meta charset='utf-8'>
<script src='https://www.w3.org/Tools/respec/respec-w3c' async class=
'remove'></script>
<script class='remove'>
var respecConfig = {
shortName: "beacon",
specStatus: "ED",
crEnd: "2017-05-11",
useExperimentalStyles: true,
edDraftURI: "https://w3c.github.io/beacon/",
editors: [{
name: "Ilya Grigorik",
mailto: "[email protected]",
company: "Shopify",
w3cid: "56102"
}, {
name: "Alois Reitbauer",
mailto: "[email protected]",
company: "Compuware Corp.",
w3cid: "48276"
}, {
name: "Arvind Jain",
mailto: "[email protected]",
company: "Google Inc.",
retiredDate: "2015-01-01",
w3cid: "45188"
}, {
name: "Jatinder Mann",
mailto: "[email protected]",
company: "Microsoft Corp.",
retiredDate: "2014-02-01",
w3cid: "44357"
}],
group: "webperf",
license: 'w3c-software-doc',
wgPublicList: "public-web-perf",
noLegacyStyle: true,
github: "https://github.com/w3c/beacon",
testSuiteURI: "https://w3c-test.org/beacon/",
implementationReportURI: "https://w3c.github.io/test-results/beacon/",
otherLinks: [{
key: 'Implementation',
data: [{
value: 'Can I use Beacon?',
href: 'http://caniuse.com/#feat=beacon'
}]
}],
xref: ["html", "fetch", "url", "webidl"]
};
</script>
</head>
<body data-link-for="Navigator">
<section id="abstract">
<p>This specification defines an interface that web developers can use to
schedule asynchronous and non-blocking delivery of data that minimizes
resource contention with other time-critical operations, while ensuring
that such requests are still processed and delivered to destination.</p>
</section>
<section id='sotd'></section>
<section id="introduction" class='informative'>
<h2>Introduction</h2>
<p>Web applications often need to issue requests that report events, state
updates, and analytics to one or more servers. Such requests typically do
not require response processing on the client (e.g. result in 204, or 200
HTTP response codes with an empty response body), and should not compete
for network and compute resources with other high priority operations such
as fetching critical resources, reacting to input, running animations, and
so on. However, such one-way requests (beacons), are also responsible for
delivering critical application and measurement data, forcing developers to
use costly methods to ensure their delivery:</p>
<ul>
<li>Developers opt for immediate delivery of each beacon, instead of
coalescing and deferring their delivery because this provides improved
delivery rates. Deferring delivery may mean that the beacon request may
not have sufficient time to complete successfully, which leads to loss of
important application data.</li>
<li>Developers opt for issuing blocking requests via synchronous
XMLHttpRequest's, inserting no-op busy loops, or using other techniques
that block the user agent from executing time-critical operations (e.g.
click, unload, and other handlers) and hurt the user experience. The
blocking behavior is used to provide improved delivery rate, as it
prevents the user agent and the operating system from cancelling the
request if the page is unloaded, suspended, or killed by the system.</li>
</ul>
<p>The mismatch between above delivery and processing requirements leaves
most developers with a tough choice and widespread adoption of blocking
techniques that hurt the user experience. This specification defines an
interface that web developers can use to schedule asynchronous and
non-blocking delivery of data that minimizes resource contention with other
time-critical operations, while ensuring that such requests are still
processed and delivered to destination:</p>
<ul>
<li>Beacon requests are prioritized to avoid competing with time-critical
operations and higher priority network requests.</li>
<li>Beacon requests may be efficiently coalesced by the user agent to
optimize energy use on mobile devices.</li>
<li>Beacon requests are guaranteed to be initiated before page is
unloaded and are allowed to run to completion without requiring blocking
requests or other techniques that block processing of user interactive
events.</li>
</ul>
<p>The following example shows use of the <a>sendBeacon()</a> method to
deliver event, click, and analytics data:</p>
<pre class='example highlight'>
<html>
<script>
// emit non-blocking beacon to record client-side event
function reportEvent(event) {
var data = JSON.stringify({
event: event,
time: performance.now()
});
navigator.sendBeacon('/collector', data);
}
// emit non-blocking beacon with session analytics as the page
// transitions to background state (Page Visibility API)
document.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'hidden') {
var sessionData = buildSessionReport();
navigator.sendBeacon('/collector', sessionData);
}
});
</script>
<body>
<a href='http://www.w3.org/' onclick='reportEvent(this)'>
<button onclick="reportEvent('some event')">Click me</button>
</body>
</html>
</pre>
<p class="note">Above example uses [=Document/visibilitychange=]
event defined in [[PAGE-VISIBILITY-2]] to trigger delivery of session data.
This event is the only event that is guaranteed to fire on mobile devices
when the page transitions to background state (e.g. when user switches to a
different application, goes to homescreen, etc), or is being unloaded.
Developers should avoid relying on [=Window/unload=] event because it will
not fire whenever a page is in a background state (i.e.
{{Document/visibilityState}} equal to {{Document/hidden}} and the process is
terminated by the mobile OS.</p>
<p>The requests initiated via the <a>sendBeacon()</a> method do not block
or compete with time-critical work, may be prioritized by the user agent to
improve network efficiency, and eliminate the need to use blocking
operations to ensure delivery of beacon data.</p>
<p>What <a>sendBeacon()</a> does not do and is not intended to solve:</p>
<ul>
<li>The <a>sendBeacon()</a> method does not provide special handling for
offline storage or delivery. A beacon request is like any other request
and may be combined with [[SERVICE-WORKERS]] to provide offline
functionality where necessary.
</li>
<li>The <a>sendBeacon()</a> method is not intended to provide background
synchronization or transfer capabilities. The user agent restricts the
maximum accepted payload size to ensure that beacon requests are able to
complete quickly and in a timely manner.
</li>
<li>The <a>sendBeacon()</a> method does not provide ability to customize
the request method, provide custom request headers, or change other
<a href="#sec-processing-model">processing properties</a> of the request
and response. Applications that require non-default settings for such
requests should use the [[FETCH]] API with [=request/keepalive=] set to
<code>true</code>.
</li>
</ul>
</section>
<section id='conformance'>
<p>For readability, these words do not appear in all uppercase letters in
this specification.</p>
<p>Requirements phrased in the imperative as part of algorithms (such as
"strip any leading space characters" or "return false and abort these
steps") are to be interpreted with the meaning of the key word ("must",
"should", "may", etc) used in introducing the algorithm.</p>
<p>Some conformance requirements are phrased as requirements on attributes,
methods or objects. Such requirements are to be interpreted as requirements
on the user agent.</p>
<p>Conformance requirements phrased as algorithms or specific steps may be
implemented in any manner, so long as the end result is equivalent. (In
particular, the algorithms defined in this specification are intended to be
easy to follow, and not intended to be performant.)</p>
</section>
<section>
<h2>Beacon</h2>
<section data-dfn-for="Navigator" data-link-for="Navigator">
<h3><code><dfn>sendBeacon()</dfn></code> Method</h3>
<pre class="idl">
partial interface Navigator {
boolean sendBeacon(USVString url, optional BodyInit? data = null);
};
</pre>
<p>The <a>sendBeacon()</a> method transmits data provided by the
<a><code>data</code></a> parameter to the URL provided by the <a href=
"#url-parameter"><code>url</code></a> parameter:</p>
<ul>
<li>The user agent MUST initiate a fetch with [=request/keepalive=]
flag set, which restricts the amount of data that can be queued by such
requests to ensure that beacon requests are able to complete quickly and
in a timely manner.
</li>
<li>The user agent MUST schedule immediate transmission of all beacon
requests when the document {{Document/visibilityState}} transitions to
{{Document/hidden}}, and must allow all such requests to run to
completion without blocking other time-critical and high-priority work.
</li>
<li>The user agent SHOULD schedule transmission of provided data to
minimize resource (CPU and network) contention with other time-critical
and high priority work.</li>
<li>The user agent MAY delay transmission of provided data to optimize
network and energy efficiency - e.g. deliver immediately if the network
is active, or wait until network interface is active. However, the user
agent SHOULD NOT delay transmission indefinitely and ensure that
pending transmissions are periodically flushed even if there is no
other network activity.</li>
</ul>
<div class="note">
Beacon API does not provide a response callback. The server is
encouraged to omit returning a response body for such requests (e.g.
respond with <code>204 No Content</code>).
</div>
<div>
<h4>Parameters</h4>
<h4><dfn id="url-parameter" data-lt-nodefault="" data-lt=
"url parameter"><code>url</code></dfn></h4>
<p>The <a href="#url-parameter"><code>url</code></a> parameter
indicates the URL where the data is to be transmitted.</p>
<h4><dfn><code>data</code></dfn></h4>
<p>The <a><code>data</code></a> parameter is the {{BodyInit}} data
that is to be transmitted.</p>
</div>
<div>
<h4>Return Value</h4>
<p>The <a>sendBeacon()</a> method returns true if the user agent is
able to successfully queue the data for transfer. Otherwise it returns
false.</p>
<p class="note">The user agent imposes limits on the amount of data
that can be sent via this API: this helps ensure that such requests are
delivered successfully and with minimal impact on other user and
browser activity. If the amount of <var>data</var> to be queued exceeds
the user agent limit (as defined in <a
data-cite="!fetch#concept-http-network-or-cache-fetch">HTTP-network-or-cache
fetch</a>), this method returns <code>false</code>; a return value of
<code>true</code> implies the browser has queued the data for transfer.
However, since the actual data transfer happens asynchronously, this
method does not provide any information whether the data transfer has
succeeded or not.</p>
</div>
</section>
<section id="sec-processing-model">
<h2>Processing Model</h2>
<p>On calling the <a>sendBeacon()</a> method with <var>url</var> and
optional <var>data</var>, the following steps must be run:</p>
<ol>
<li>
<p>Set <var>base</var> to [=this=]'s [=relevant settings object=]'s
[=environment settings object/API base URL=].</p>
</li>
<li>
<p>Set <var>origin</var> to [=this=]'s [=relevant settings object=]'s
[=environment settings object/origin=].</p>
</li>
<li>
<p>Set <var>parsedUrl</var> to the result of the <a>URL parser</a>
steps with <var>url</var> and <var>base</var>. If the algorithm
returns an error, or if <var>parsedUrl</var>'s [=url/scheme=] is not
"http" or "https", [=exception/throw=] a
"<code>{{TypeError}}</code>" exception and terminate these
steps.</p>
</li>
<li>Let <var>headerList</var> be an empty list.</li>
<li>Let <var>corsMode</var> be "<code>no-cors</code>".</li>
<li>
<p>If <var>data</var> is not <code>null</code>:</p>
<ol>
<li>Set <var>transmittedData</var> and <var>contentType</var> to the
result of [=BodyInit/extract|extracting=] <var>data</var>'s
byte stream with the <var>keepalive flag</var> set.
</li>
<li>If the amount of data that can be queued to be sent by
[=request/keepalive=] enabled requests is exceeded by the size of
<var>transmittedData</var> (as defined in <a
data-cite="!fetch#concept-http-network-or-cache-fetch">HTTP-network-or-cache
fetch</a>), set the return value to <code>false</code> and
terminate these steps.
<p class="note">Requests initiated via the Beacon API automatically
set the [=request/keepalive=] flag, and developers can similarly
set the same flag manually when using the Fetch API. All requests
with this flag set share the same in-flight quota restrictions
that is enforced within the Fetch API.</p>
</li>
<li>If <var>contentType</var> is not null:
<ul>
<li>Set <var>corsMode</var> to "<code>cors</code>".</li>
<li>If <var>contentType</var> value is a <a>CORS-safelisted
request-header</a> value for the <code>Content-Type</code>
header, set <var>corsMode</var> to "<code>no-cors</code>".
</li>
<li>Append a <code>Content-Type</code> header with value
<var>contentType</var> to <var>headerList</var>.</li>
</ul>
</li>
</ol>
</li>
<li>Set the return value to <code>true</code>, return the
<a>sendBeacon()</a> call, and continue to run the following steps in
parallel:
<ol>
<li>
<p>Let <var>req</var> be a new <a>request</a>, initialized as
follows:</p>
<dl>
<dt>
[=request/method=]
</dt>
<dd><code>POST</code></dd>
<dt>
[=request/client=]
</dt>
<dd>[=this=]'s [=relevant settings object=]</dd>
<dt>
[=request/url=]
</dt>
<dd><var>parsedUrl</var></dd>
<dt>
[=request/header list=]
</dt>
<dd><var>headerList</var></dd>
<dt>
[=request/origin=]
</dt>
<dd><i>origin</i></dd>
<dt>
[=request/keepalive=]
</dt>
<dd><code>true</code></dd>
<dt>
[=request/body=]
</dt>
<dd><var>transmittedData</var></dd>
<dt>
[=request/mode=]
</dt>
<dd><var>corsMode</var></dd>
<dt>
[=request/credentials mode=]
</dt>
<dd><i>include</i></dd>
<dt>
[=request/initiator type=]
</dt>
<dd>"<code>beacon</code>"</dd>
</dl>
</li>
<li>
<a>Fetch</a> <var>req</var>.
</li>
</ol>
</li>
</ol>
</section>
</section>
<section>
<h2>Privacy and Security</h2>
<p>The <a>sendBeacon()</a> interface provides an asynchronous and
non-blocking mechanism for delivery of data. This API can be used to:</p>
<ul>
<li>Report client-side events to the server. The delivery is prioritized
and scheduled by the user agent such that it does not block other
interactive work and makes efficient use of system resources.</li>
<li>Report session data when the page transitions to background state or
is being unloaded, without blocking the user agent.</li>
<li>Other use cases that require delivery of small payloads and do not
expect a response callback.</li>
</ul>
<p>The delivered data might contain potentially sensitive information, for
example, data about a user's activity on a web page, to a server. While
this can have privacy implications for the user, existing methods, such as
scripted form-submit, image beacons, and XHR/fetch requests provide similar
capabilities, but come with various and costly performance tradeoffs: the
requests can be aborted by the user agent unless the developer blocks the
user agent from processing other events (e.g. by invoking a synchronous
request, or spinning in an empty loop), and the user agent is unable to
prioritize and coalesce such requests to optimize use of system
resources.</p>
<p>A request initiated by <a>sendBeacon()</a> is subject to following
properties:</p>
<ul>
<li>If the request does not contain a payload, or the request
<code>Content-Type</code> is a <a>CORS-safelisted request-header</a>,
then the request mode is `no-cors`—similar to an image beacon or
form-post respectively.
</li>
<li>Otherwise, a CORS preflight is made and the server needs to first
allow such requests by returning the appropriate set of CORS headers:
<a data-cite="!fetch#http-access-control-allow-credentials">
<code>Access-Control-Allow-Credentials</code></a>,
<a data-cite="!fetch#http-access-control-allow-origin">
<code>Access-Control-Allow-Origin</code></a>,
<a data-cite="!fetch#http-access-control-allow-headers">
<code>Access-Control-Allow-Headers</code></a>.
</li>
</ul>
<p>As such, from the security perspective, the Beacon API is subject to
same security policies as the current methods in use by developers.
Similarly, from the privacy perspective, the resulting requests are
initiated immediately when the API is called, or upon a page visibility
change, which restricts the exposed information (e.g. user's IP address) to
existing lifecycle events accessible to the developers. However, user
agents might consider alternative methods to surface such requests to
provide transparency to users.</p>
<p>Compared to the alternatives, the <a>sendBeacon()</a> API does apply two
restrictions: there is no callback method, and the payload size can be
restricted by the user agent. Otherwise, the <a>sendBeacon()</a> API is not
subject to any additional restrictions. The user agent ought not skip or
throttle processing of <a>sendBeacon()</a> calls, as they can contain
critical application state, events, and analytics data. Similarly, the user
agent ought not disable <a>sendBeacon()</a> when in "private browsing" or
equivalent mode, both to avoid breaking the application and to avoid
leaking that the user is in such mode.</p>
</section>
<section class="appendix">
<h2>Acknowledgments</h2>
<p>Thanks to Alois Reitbauer, Arvind Jain, Anne van Kesteren, Boris
Zbarsky, Chase Douglas, Daniel Austin, Jatinder Mann, James Simonsen, Jason
Weber, Jonas Sicking, Nick Doty, Philippe Le Hegaret, Todd Reifsteck, Tony
Gentilcore, William Chan, and Yoav Weiss for their contributions to this
work.</p>
</section>
</body>
</html>