1
|
|
2
|
# SockJS-client
|
3
|
|
4
|
[](https://www.npmjs.com/package/sockjs-client)[](https://travis-ci.org/sockjs/sockjs-client)[](https://david-dm.org/sockjs/sockjs-client)[](https://gitter.im/sockjs/sockjs-client)
|
5
|
[](https://www.browserstack.com/automate/public-build/dW9YdlFsSEI5VzNBVVk5ZS9XT0xaTjJVQkhQMkRkNlZBQURiSWNWMC9jaz0tLXRJM05RbW1tTCt5TlhHaVgycFJUYmc9PQ==--e3ef9b9a9fa071084e6d87874b5fc65b71273821)
|
6
|
|
7
|
# Supporting SockJS
|
8
|
|
9
|
Tidelift gives software development teams a single source for purchasing and maintaining their software, with professional grade assurances from the experts who know it best, while seamlessly integrating with existing tools.
|
10
|
|
11
|
[Get supported sockjs-client with the Tidelift Subscription](https://tidelift.com/subscription/pkg/npm-sockjs-client?utm_source=npm-sockjs-client&utm_medium=referral&utm_campaign=readme)
|
12
|
|
13
|
# Summary
|
14
|
|
15
|
SockJS is a browser JavaScript library that provides a WebSocket-like
|
16
|
object. SockJS gives you a coherent, cross-browser, Javascript API
|
17
|
which creates a low latency, full duplex, cross-domain communication
|
18
|
channel between the browser and the web server.
|
19
|
|
20
|
Under the hood SockJS tries to use native WebSockets first. If that
|
21
|
fails it can use a variety of browser-specific transport protocols and
|
22
|
presents them through WebSocket-like abstractions.
|
23
|
|
24
|
SockJS is intended to work for all modern browsers and in environments
|
25
|
which don't support the WebSocket protocol -- for example, behind restrictive
|
26
|
corporate proxies.
|
27
|
|
28
|
SockJS-client does require a server counterpart:
|
29
|
|
30
|
* [SockJS-node](https://github.com/sockjs/sockjs-node) is a SockJS
|
31
|
server for Node.js.
|
32
|
|
33
|
|
34
|
Philosophy:
|
35
|
|
36
|
* The API should follow
|
37
|
[HTML5 Websockets API](https://www.w3.org/TR/websockets/) as
|
38
|
closely as possible.
|
39
|
* All the transports must support cross domain connections out of the
|
40
|
box. It's possible and recommended to host a SockJS server on a
|
41
|
different server than your main web site.
|
42
|
* There is support for at least one streaming protocol for every
|
43
|
major browser.
|
44
|
* Streaming transports should work cross-domain and
|
45
|
should support cookies (for cookie-based sticky sessions).
|
46
|
* Polling transports are used as a fallback for old browsers and
|
47
|
hosts behind restrictive proxies.
|
48
|
* Connection establishment should be fast and lightweight.
|
49
|
* No Flash inside (no need to open port 843 - which doesn't work
|
50
|
through proxies, no need to host 'crossdomain.xml', no need
|
51
|
[to wait for 3 seconds](https://github.com/gimite/web-socket-js/issues/49)
|
52
|
in order to detect problems)
|
53
|
|
54
|
|
55
|
Subscribe to
|
56
|
[SockJS mailing list](https://groups.google.com/forum/#!forum/sockjs) for
|
57
|
discussions and support.
|
58
|
|
59
|
# SockJS family
|
60
|
|
61
|
* [SockJS-client](https://github.com/sockjs/sockjs-client) JavaScript client library
|
62
|
* [SockJS-node](https://github.com/sockjs/sockjs-node) Node.js server
|
63
|
* [SockJS-erlang](https://github.com/sockjs/sockjs-erlang) Erlang server
|
64
|
* [SockJS-cyclone](https://github.com/flaviogrossi/sockjs-cyclone) Python/Cyclone/Twisted server
|
65
|
* [SockJS-tornado](https://github.com/MrJoes/sockjs-tornado) Python/Tornado server
|
66
|
* [SockJS-twisted](https://github.com/DesertBus/sockjs-twisted/) Python/Twisted server
|
67
|
* [SockJS-aiohttp](https://github.com/aio-libs/sockjs/) Python/Aiohttp server
|
68
|
* [Spring Framework](https://projects.spring.io/spring-framework) Java [client](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html#websocket-fallback-sockjs-client) & server
|
69
|
* [vert.x](https://github.com/vert-x/vert.x) Java/vert.x server
|
70
|
* [Xitrum](https://xitrum-framework.github.io/) Scala server
|
71
|
* [Atmosphere Framework](https://github.com/Atmosphere/atmosphere) JavaEE Server, Play Framework, Netty, Vert.x
|
72
|
* [Actix SockJS](https://github.com/fafhrd91/actix-sockjs) Rust Server, Actix Framework
|
73
|
|
74
|
Work in progress:
|
75
|
|
76
|
* [SockJS-ruby](https://github.com/nyarly/sockjs-ruby)
|
77
|
* [SockJS-netty](https://github.com/cgbystrom/sockjs-netty)
|
78
|
* [SockJS-gevent](https://github.com/ksava/sockjs-gevent) ([SockJS-gevent fork](https://github.com/njoyce/sockjs-gevent))
|
79
|
* [pyramid-SockJS](https://github.com/fafhrd91/pyramid_sockjs)
|
80
|
* [wildcloud-websockets](https://github.com/wildcloud/wildcloud-websockets)
|
81
|
* [wai-SockJS](https://github.com/Palmik/wai-sockjs)
|
82
|
* [SockJS-perl](https://github.com/vti/sockjs-perl)
|
83
|
* [SockJS-go](https://github.com/igm/sockjs-go/)
|
84
|
* [syp.biz.SockJS.NET](https://github.com/sypbiz/SockJS.NET) - .NET port of the SockJS client
|
85
|
|
86
|
# Getting Started
|
87
|
|
88
|
SockJS mimics the [WebSockets API](https://www.w3.org/TR/websockets/),
|
89
|
but instead of `WebSocket` there is a `SockJS` Javascript object.
|
90
|
|
91
|
First, you need to load the SockJS JavaScript library. For example, you can
|
92
|
put that in your HTML head:
|
93
|
|
94
|
```html
|
95
|
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
96
|
```
|
97
|
|
98
|
After the script is loaded you can establish a connection with the
|
99
|
SockJS server. Here's a simple example:
|
100
|
|
101
|
```javascript
|
102
|
var sock = new SockJS('https://mydomain.com/my_prefix');
|
103
|
sock.onopen = function() {
|
104
|
console.log('open');
|
105
|
sock.send('test');
|
106
|
};
|
107
|
|
108
|
sock.onmessage = function(e) {
|
109
|
console.log('message', e.data);
|
110
|
sock.close();
|
111
|
};
|
112
|
|
113
|
sock.onclose = function() {
|
114
|
console.log('close');
|
115
|
};
|
116
|
|
117
|
```
|
118
|
|
119
|
# SockJS-client API
|
120
|
|
121
|
## SockJS class
|
122
|
|
123
|
Similar to the 'WebSocket' API, the 'SockJS' constructor takes one, or more arguments:
|
124
|
|
125
|
```javascript
|
126
|
var sockjs = new SockJS(url, _reserved, options);
|
127
|
```
|
128
|
|
129
|
`url` may contain a query string, if one is desired.
|
130
|
|
131
|
Where `options` is a hash which can contain:
|
132
|
|
133
|
* **server (string)**
|
134
|
|
135
|
String to append to url for actual data connection. Defaults to a random 4 digit number.
|
136
|
|
137
|
* **transports (string OR array of strings)**
|
138
|
|
139
|
Sometimes it is useful to disable some fallback transports. This
|
140
|
option allows you to supply a list transports that may be used by
|
141
|
SockJS. By default all available transports will be used.
|
142
|
|
143
|
* **sessionId (number OR function)**
|
144
|
|
145
|
Both client and server use session identifiers to distinguish connections.
|
146
|
If you specify this option as a number, SockJS will use its random string
|
147
|
generator function to generate session ids that are N-character long
|
148
|
(where N corresponds to the number specified by **sessionId**).
|
149
|
When you specify this option as a function, the function must return a
|
150
|
randomly generated string. Every time SockJS needs to generate a session
|
151
|
id it will call this function and use the returned string directly.
|
152
|
If you don't specify this option, the default is to use the default random
|
153
|
string generator to generate 8-character long session ids.
|
154
|
|
155
|
* **timeout (number)**
|
156
|
|
157
|
Specify a minimum timeout in milliseconds to use for the transport connections.
|
158
|
By default this is dynamically calculated based on the measured RTT and
|
159
|
the number of expected round trips. This setting will establish a minimum,
|
160
|
but if the calculated timeout is higher, that will be used.
|
161
|
|
162
|
Although the 'SockJS' object tries to emulate the 'WebSocket'
|
163
|
behaviour, it's impossible to support all of its features. An
|
164
|
important SockJS limitation is the fact that you're not allowed to
|
165
|
open more than one SockJS connection to a single domain at a time.
|
166
|
This limitation is caused by an in-browser limit of outgoing
|
167
|
connections - usually [browsers don't allow opening more than two
|
168
|
outgoing connections to a single domain](https://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser). A single SockJS session
|
169
|
requires those two connections - one for downloading data, the other for
|
170
|
sending messages. Opening a second SockJS session at the same time
|
171
|
would most likely block, and can result in both sessions timing out.
|
172
|
|
173
|
Opening more than one SockJS connection at a time is generally a
|
174
|
bad practice. If you absolutely must do it, you can use
|
175
|
multiple subdomains, using a different subdomain for every
|
176
|
SockJS connection.
|
177
|
|
178
|
# Supported transports, by browser (html served from http:// or https://)
|
179
|
|
180
|
_Browser_ | _Websockets_ | _Streaming_ | _Polling_
|
181
|
----------------|------------------|-------------|-------------------
|
182
|
IE 6, 7 | no | no | jsonp-polling
|
183
|
IE 8, 9 (cookies=no) | no | xdr-streaming † | xdr-polling †
|
184
|
IE 8, 9 (cookies=yes)| no | iframe-htmlfile | iframe-xhr-polling
|
185
|
IE 10 | rfc6455 | xhr-streaming | xhr-polling
|
186
|
Chrome 6-13 | hixie-76 | xhr-streaming | xhr-polling
|
187
|
Chrome 14+ | hybi-10 / rfc6455| xhr-streaming | xhr-polling
|
188
|
Firefox <10 | no ‡ | xhr-streaming | xhr-polling
|
189
|
Firefox 10+ | hybi-10 / rfc6455| xhr-streaming | xhr-polling
|
190
|
Safari 5.x | hixie-76 | xhr-streaming | xhr-polling
|
191
|
Safari 6+ | rfc6455 | xhr-streaming | xhr-polling
|
192
|
Opera 10.70+ | no ‡ | iframe-eventsource | iframe-xhr-polling
|
193
|
Opera 12.10+ | rfc6455 | xhr-streaming | xhr-polling
|
194
|
Konqueror | no | no | jsonp-polling
|
195
|
|
196
|
|
197
|
* **†**: IE 8+ supports [XDomainRequest][^9], which is
|
198
|
essentially a modified AJAX/XHR that can do requests across
|
199
|
domains. But unfortunately it doesn't send any cookies, which
|
200
|
makes it inappropriate for deployments when the load balancer uses
|
201
|
JSESSIONID cookie to do sticky sessions.
|
202
|
|
203
|
* **‡**: Firefox 4.0 and Opera 11.00 and shipped with disabled
|
204
|
Websockets "hixie-76". They can still be enabled by manually
|
205
|
changing a browser setting.
|
206
|
|
207
|
# Supported transports, by browser (html served from file://)
|
208
|
|
209
|
Sometimes you may want to serve your html from "file://" address - for
|
210
|
development or if you're using PhoneGap or similar technologies. But
|
211
|
due to the Cross Origin Policy files served from "file://" have no
|
212
|
Origin, and that means some of SockJS transports won't work. For this
|
213
|
reason the SockJS transport table is different than usually, major
|
214
|
differences are:
|
215
|
|
216
|
_Browser_ | _Websockets_ | _Streaming_ | _Polling_
|
217
|
----------------|---------------|--------------------|-------------------
|
218
|
IE 8, 9 | same as above | iframe-htmlfile | iframe-xhr-polling
|
219
|
Other | same as above | iframe-eventsource | iframe-xhr-polling
|
220
|
|
221
|
# Supported transports, by name
|
222
|
|
223
|
_Transport_ | _References_
|
224
|
---------------------|---------------
|
225
|
websocket (rfc6455) | [rfc 6455][^10]
|
226
|
websocket (hixie-76) | [draft-hixie-thewebsocketprotocol-76][^1]
|
227
|
websocket (hybi-10) | [draft-ietf-hybi-thewebsocketprotocol-10][^2]
|
228
|
xhr-streaming | Transport using [Cross domain XHR][^5] [streaming][^7] capability (readyState=3).
|
229
|
xdr-streaming | Transport using [XDomainRequest][^9] [streaming][^7] capability (readyState=3).
|
230
|
eventsource | [EventSource/Server-sent events][^4].
|
231
|
iframe-eventsource | [EventSource/Server-sent events][^4] used from an [iframe via postMessage][^3].
|
232
|
htmlfile | [HtmlFile][^8].
|
233
|
iframe-htmlfile | [HtmlFile][^8] used from an [iframe via postMessage][^3].
|
234
|
xhr-polling | Long-polling using [cross domain XHR][^5].
|
235
|
xdr-polling | Long-polling using [XDomainRequest][^9].
|
236
|
iframe-xhr-polling | Long-polling using normal AJAX from an [iframe via postMessage][^3].
|
237
|
jsonp-polling | Slow and old fashioned [JSONP polling][^6]. This transport will show "busy indicator" (aka: "spinning wheel") when sending data.
|
238
|
|
239
|
|
240
|
[^1]: https://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76
|
241
|
[^2]: https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
|
242
|
[^3]: https://developer.mozilla.org/en/DOM/window.postMessage
|
243
|
[^4]: https://html.spec.whatwg.org/multipage/comms.html#server-sent-events
|
244
|
[^5]: https://secure.wikimedia.org/wikipedia/en/wiki/XMLHttpRequest#Cross-domain_requests
|
245
|
[^6]: https://secure.wikimedia.org/wikipedia/en/wiki/JSONP
|
246
|
[^7]: http://www.debugtheweb.com/test/teststreaming.aspx
|
247
|
[^8]: http://cometdaily.com/2007/11/18/ie-activexhtmlfile-transport-part-ii/
|
248
|
[^9]: https://blogs.msdn.microsoft.com/ieinternals/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds/
|
249
|
[^10]: https://www.rfc-editor.org/rfc/rfc6455.txt
|
250
|
|
251
|
|
252
|
# Connecting to SockJS without the client
|
253
|
|
254
|
Although the main point of SockJS is to enable browser-to-server
|
255
|
connectivity, it is possible to connect to SockJS from an external
|
256
|
application. Any SockJS server complying with 0.3 protocol does
|
257
|
support a raw WebSocket url. The raw WebSocket url for the test server
|
258
|
looks like:
|
259
|
|
260
|
* ws://localhost:8081/echo/websocket
|
261
|
|
262
|
You can connect any WebSocket RFC 6455 compliant WebSocket client to
|
263
|
this url. This can be a command line client, external application,
|
264
|
third party code or even a browser (though I don't know why you would
|
265
|
want to do so).
|
266
|
|
267
|
|
268
|
# Deployment
|
269
|
|
270
|
You should use a version of sockjs-client
|
271
|
that supports the protocol used by your server. For example:
|
272
|
|
273
|
```html
|
274
|
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
275
|
```
|
276
|
|
277
|
|
278
|
For server-side deployment tricks, especially about load balancing and
|
279
|
session stickiness, take a look at the
|
280
|
[SockJS-node readme](https://github.com/sockjs/sockjs-node#readme).
|
281
|
|
282
|
|
283
|
# Development and testing
|
284
|
|
285
|
SockJS-client needs [node.js](https://nodejs.org/) for running a test
|
286
|
server and JavaScript minification. If you want to work on
|
287
|
SockJS-client source code, checkout the git repo and follow these
|
288
|
steps:
|
289
|
|
290
|
cd sockjs-client
|
291
|
npm install
|
292
|
|
293
|
To generate JavaScript, run:
|
294
|
|
295
|
gulp browserify
|
296
|
|
297
|
To generate minified JavaScript, run:
|
298
|
|
299
|
gulp browserify:min
|
300
|
|
301
|
Both commands output into the `build` directory.
|
302
|
|
303
|
## Testing
|
304
|
|
305
|
Automated testing provided by:
|
306
|
|
307
|
<a href="https://browserstack.com"><img src="img/Browserstack-logo@2x.png" height="50"></a>
|
308
|
|
309
|
Once you've compiled the SockJS-client you may want to check if your changes
|
310
|
pass all the tests.
|
311
|
|
312
|
npm run test:browser_local
|
313
|
|
314
|
This will start [karma](https://karma-runner.github.io) and a test support server.
|
315
|
|
316
|
# Browser Quirks
|
317
|
|
318
|
There are various browser quirks which we don't intend to address:
|
319
|
|
320
|
* Pressing ESC in Firefox, before Firefox 20, closes the SockJS connection. For a workaround
|
321
|
and discussion see [#18](https://github.com/sockjs/sockjs-client/issues/18).
|
322
|
* `jsonp-polling` transport will show a "spinning wheel" (aka. "busy indicator")
|
323
|
when sending data.
|
324
|
* You can't open more than one SockJS connection to one domain at the
|
325
|
same time due to [the browser's limit of concurrent connections](https://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser)
|
326
|
(this limit is not counting native WebSocket connections).
|
327
|
* Although SockJS is trying to escape any strange Unicode characters
|
328
|
(even invalid ones - [like surrogates \xD800-\xDBFF](https://en.wikipedia.org/wiki/Mapping_of_Unicode_characters#Surrogates) or [\xFFFE and \xFFFF](https://en.wikipedia.org/wiki/Unicode#Character_General_Category))
|
329
|
it's advisable to use only valid characters. Using invalid
|
330
|
characters is a bit slower, and may not work with SockJS servers
|
331
|
that have proper Unicode support.
|
332
|
* Having a global function called `onmessage` or such is probably a
|
333
|
bad idea, as it could be called by the built-in `postMessage` API.
|
334
|
* From SockJS' point of view there is nothing special about
|
335
|
SSL/HTTPS. Connecting between unencrypted and encrypted sites
|
336
|
should work just fine.
|
337
|
* Although SockJS does its best to support both prefix and cookie based
|
338
|
sticky sessions, the latter may not work well cross-domain with
|
339
|
browsers that don't accept third-party cookies by default (Safari).
|
340
|
In order to get around this make sure you're connecting to SockJS
|
341
|
from the same parent domain as the main site. For example
|
342
|
'sockjs.a.com' is able to set cookies if you're connecting from
|
343
|
'www.a.com' or 'a.com'.
|
344
|
* Trying to connect from secure "https://" to insecure "http://" is
|
345
|
not a good idea. The other way around should be fine.
|
346
|
* Long polling is known to cause problems on Heroku, but a
|
347
|
[workaround for SockJS is available](https://github.com/sockjs/sockjs-node/issues/57#issuecomment-5242187).
|
348
|
* SockJS [websocket transport is more stable over SSL](https://github.com/sockjs/sockjs-client/issues/94). If
|
349
|
you're a serious SockJS user then consider using SSL
|
350
|
([more info](https://www.ietf.org/mail-archive/web/hybi/current/msg01605.html)).
|