| |
| # SockJS-client |
| |
| [](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) |
| [](https://www.browserstack.com/automate/public-build/dW9YdlFsSEI5VzNBVVk5ZS9XT0xaTjJVQkhQMkRkNlZBQURiSWNWMC9jaz0tLXRJM05RbW1tTCt5TlhHaVgycFJUYmc9PQ==--e3ef9b9a9fa071084e6d87874b5fc65b71273821) |
| |
| SockJS is a browser JavaScript library that provides a WebSocket-like |
| object. SockJS gives you a coherent, cross-browser, Javascript API |
| which creates a low latency, full duplex, cross-domain communication |
| channel between the browser and the web server. |
| |
| Under the hood SockJS tries to use native WebSockets first. If that |
| fails it can use a variety of browser-specific transport protocols and |
| presents them through WebSocket-like abstractions. |
| |
| SockJS is intended to work for all modern browsers and in environments |
| which don't support the WebSocket protocol -- for example, behind restrictive |
| corporate proxies. |
| |
| SockJS-client does require a server counterpart: |
| |
| * [SockJS-node](https://github.com/sockjs/sockjs-node) is a SockJS |
| server for Node.js. |
| |
| |
| Philosophy: |
| |
| * The API should follow |
| [HTML5 Websockets API](https://www.w3.org/TR/websockets/) as |
| closely as possible. |
| * All the transports must support cross domain connections out of the |
| box. It's possible and recommended to host a SockJS server on a |
| different server than your main web site. |
| * There is support for at least one streaming protocol for every |
| major browser. |
| * Streaming transports should work cross-domain and |
| should support cookies (for cookie-based sticky sessions). |
| * Polling transports are used as a fallback for old browsers and |
| hosts behind restrictive proxies. |
| * Connection establishment should be fast and lightweight. |
| * No Flash inside (no need to open port 843 - which doesn't work |
| through proxies, no need to host 'crossdomain.xml', no need |
| [to wait for 3 seconds](https://github.com/gimite/web-socket-js/issues/49) |
| in order to detect problems) |
| |
| |
| Subscribe to |
| [SockJS mailing list](https://groups.google.com/forum/#!forum/sockjs) for |
| discussions and support. |
| |
| SockJS family: |
| |
| * [SockJS-client](https://github.com/sockjs/sockjs-client) JavaScript client library |
| * [SockJS-node](https://github.com/sockjs/sockjs-node) Node.js server |
| * [SockJS-erlang](https://github.com/sockjs/sockjs-erlang) Erlang server |
| * [SockJS-cyclone](https://github.com/flaviogrossi/sockjs-cyclone) Python/Cyclone/Twisted server |
| * [SockJS-tornado](https://github.com/MrJoes/sockjs-tornado) Python/Tornado server |
| * [SockJS-twisted](https://github.com/DesertBus/sockjs-twisted/) Python/Twisted server |
| * [SockJS-aiohttp](https://github.com/aio-libs/sockjs/) Python/Aiohttp server |
| * [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 |
| * [vert.x](https://github.com/vert-x/vert.x) Java/vert.x server |
| * [Xitrum](https://xitrum-framework.github.io/) Scala server |
| * [Atmosphere Framework](https://github.com/Atmosphere/atmosphere) JavaEE Server, Play Framework, Netty, Vert.x |
| * [Actix SockJS](https://github.com/fafhrd91/actix-sockjs) Rust Server, Actix Framework |
| |
| Work in progress: |
| |
| * [SockJS-ruby](https://github.com/nyarly/sockjs-ruby) |
| * [SockJS-netty](https://github.com/cgbystrom/sockjs-netty) |
| * [SockJS-gevent](https://github.com/ksava/sockjs-gevent) ([SockJS-gevent fork](https://github.com/njoyce/sockjs-gevent)) |
| * [pyramid-SockJS](https://github.com/fafhrd91/pyramid_sockjs) |
| * [wildcloud-websockets](https://github.com/wildcloud/wildcloud-websockets) |
| * [wai-SockJS](https://github.com/Palmik/wai-sockjs) |
| * [SockJS-perl](https://github.com/vti/sockjs-perl) |
| * [SockJS-go](https://github.com/igm/sockjs-go/) |
| |
| Getting Started |
| ------- |
| |
| SockJS mimics the [WebSockets API](https://www.w3.org/TR/websockets/), |
| but instead of `WebSocket` there is a `SockJS` Javascript object. |
| |
| First, you need to load the SockJS JavaScript library. For example, you can |
| put that in your HTML head: |
| |
| ```html |
| <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script> |
| ``` |
| |
| After the script is loaded you can establish a connection with the |
| SockJS server. Here's a simple example: |
| |
| ```javascript |
| var sock = new SockJS('https://mydomain.com/my_prefix'); |
| sock.onopen = function() { |
| console.log('open'); |
| sock.send('test'); |
| }; |
| |
| sock.onmessage = function(e) { |
| console.log('message', e.data); |
| sock.close(); |
| }; |
| |
| sock.onclose = function() { |
| console.log('close'); |
| }; |
| |
| ``` |
| |
| SockJS-client API |
| ----------------- |
| |
| ### SockJS class |
| |
| Similar to the 'WebSocket' API, the 'SockJS' constructor takes one, or more arguments: |
| |
| ```javascript |
| var sockjs = new SockJS(url, _reserved, options); |
| ``` |
| |
| `url` may contain a query string, if one is desired. |
| |
| Where `options` is a hash which can contain: |
| |
| * **server (string)** |
| |
| String to append to url for actual data connection. Defaults to a random 4 digit number. |
| |
| * **transports (string OR array of strings)** |
| |
| Sometimes it is useful to disable some fallback transports. This |
| option allows you to supply a list transports that may be used by |
| SockJS. By default all available transports will be used. |
| |
| * **sessionId (number OR function)** |
| |
| Both client and server use session identifiers to distinguish connections. |
| If you specify this option as a number, SockJS will use its random string |
| generator function to generate session ids that are N-character long |
| (where N corresponds to the number specified by **sessionId**). |
| When you specify this option as a function, the function must return a |
| randomly generated string. Every time SockJS needs to generate a session |
| id it will call this function and use the returned string directly. |
| If you don't specify this option, the default is to use the default random |
| string generator to generate 8-character long session ids. |
| |
| Although the 'SockJS' object tries to emulate the 'WebSocket' |
| behaviour, it's impossible to support all of its features. An |
| important SockJS limitation is the fact that you're not allowed to |
| open more than one SockJS connection to a single domain at a time. |
| This limitation is caused by an in-browser limit of outgoing |
| connections - usually [browsers don't allow opening more than two |
| outgoing connections to a single domain](https://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser). A single SockJS session |
| requires those two connections - one for downloading data, the other for |
| sending messages. Opening a second SockJS session at the same time |
| would most likely block, and can result in both sessions timing out. |
| |
| Opening more than one SockJS connection at a time is generally a |
| bad practice. If you absolutely must do it, you can use |
| multiple subdomains, using a different subdomain for every |
| SockJS connection. |
| |
| Supported transports, by browser (html served from http:// or https://) |
| ----------------------------------------------------------------------- |
| |
| _Browser_ | _Websockets_ | _Streaming_ | _Polling_ |
| ----------------|------------------|-------------|------------------- |
| IE 6, 7 | no | no | jsonp-polling |
| IE 8, 9 (cookies=no) | no | xdr-streaming † | xdr-polling † |
| IE 8, 9 (cookies=yes)| no | iframe-htmlfile | iframe-xhr-polling |
| IE 10 | rfc6455 | xhr-streaming | xhr-polling |
| Chrome 6-13 | hixie-76 | xhr-streaming | xhr-polling |
| Chrome 14+ | hybi-10 / rfc6455| xhr-streaming | xhr-polling |
| Firefox <10 | no ‡ | xhr-streaming | xhr-polling |
| Firefox 10+ | hybi-10 / rfc6455| xhr-streaming | xhr-polling |
| Safari 5.x | hixie-76 | xhr-streaming | xhr-polling |
| Safari 6+ | rfc6455 | xhr-streaming | xhr-polling |
| Opera 10.70+ | no ‡ | iframe-eventsource | iframe-xhr-polling |
| Opera 12.10+ | rfc6455 | xhr-streaming | xhr-polling |
| Konqueror | no | no | jsonp-polling |
| |
| |
| * **†**: IE 8+ supports [XDomainRequest][^9], which is |
| essentially a modified AJAX/XHR that can do requests across |
| domains. But unfortunately it doesn't send any cookies, which |
| makes it inappropriate for deployments when the load balancer uses |
| JSESSIONID cookie to do sticky sessions. |
| |
| * **‡**: Firefox 4.0 and Opera 11.00 and shipped with disabled |
| Websockets "hixie-76". They can still be enabled by manually |
| changing a browser setting. |
| |
| Supported transports, by browser (html served from file://) |
| ----------------------------------------------------------- |
| |
| Sometimes you may want to serve your html from "file://" address - for |
| development or if you're using PhoneGap or similar technologies. But |
| due to the Cross Origin Policy files served from "file://" have no |
| Origin, and that means some of SockJS transports won't work. For this |
| reason the SockJS transport table is different than usually, major |
| differences are: |
| |
| _Browser_ | _Websockets_ | _Streaming_ | _Polling_ |
| ----------------|---------------|--------------------|------------------- |
| IE 8, 9 | same as above | iframe-htmlfile | iframe-xhr-polling |
| Other | same as above | iframe-eventsource | iframe-xhr-polling |
| |
| Supported transports, by name |
| ----------------------------- |
| |
| _Transport_ | _References_ |
| ---------------------|--------------- |
| websocket (rfc6455) | [rfc 6455][^10] |
| websocket (hixie-76) | [draft-hixie-thewebsocketprotocol-76][^1] |
| websocket (hybi-10) | [draft-ietf-hybi-thewebsocketprotocol-10][^2] |
| xhr-streaming | Transport using [Cross domain XHR][^5] [streaming][^7] capability (readyState=3). |
| xdr-streaming | Transport using [XDomainRequest][^9] [streaming][^7] capability (readyState=3). |
| eventsource | [EventSource/Server-sent events][^4]. |
| iframe-eventsource | [EventSource/Server-sent events][^4] used from an [iframe via postMessage][^3]. |
| htmlfile | [HtmlFile][^8]. |
| iframe-htmlfile | [HtmlFile][^8] used from an [iframe via postMessage][^3]. |
| xhr-polling | Long-polling using [cross domain XHR][^5]. |
| xdr-polling | Long-polling using [XDomainRequest][^9]. |
| iframe-xhr-polling | Long-polling using normal AJAX from an [iframe via postMessage][^3]. |
| jsonp-polling | Slow and old fashioned [JSONP polling][^6]. This transport will show "busy indicator" (aka: "spinning wheel") when sending data. |
| |
| |
| [^1]: https://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 |
| [^2]: https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10 |
| [^3]: https://developer.mozilla.org/en/DOM/window.postMessage |
| [^4]: https://html.spec.whatwg.org/multipage/comms.html#server-sent-events |
| [^5]: https://secure.wikimedia.org/wikipedia/en/wiki/XMLHttpRequest#Cross-domain_requests |
| [^6]: https://secure.wikimedia.org/wikipedia/en/wiki/JSONP |
| [^7]: http://www.debugtheweb.com/test/teststreaming.aspx |
| [^8]: http://cometdaily.com/2007/11/18/ie-activexhtmlfile-transport-part-ii/ |
| [^9]: https://blogs.msdn.microsoft.com/ieinternals/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds/ |
| [^10]: https://www.rfc-editor.org/rfc/rfc6455.txt |
| |
| |
| Connecting to SockJS without the client |
| --------------------------------------- |
| |
| Although the main point of SockJS is to enable browser-to-server |
| connectivity, it is possible to connect to SockJS from an external |
| application. Any SockJS server complying with 0.3 protocol does |
| support a raw WebSocket url. The raw WebSocket url for the test server |
| looks like: |
| |
| * ws://localhost:8081/echo/websocket |
| |
| You can connect any WebSocket RFC 6455 compliant WebSocket client to |
| this url. This can be a command line client, external application, |
| third party code or even a browser (though I don't know why you would |
| want to do so). |
| |
| |
| Deployment |
| ---------- |
| |
| You should use a version of sockjs-client |
| that supports the protocol used by your server. For example: |
| |
| ```html |
| <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script> |
| ``` |
| |
| |
| For server-side deployment tricks, especially about load balancing and |
| session stickiness, take a look at the |
| [SockJS-node readme](https://github.com/sockjs/sockjs-node#readme). |
| |
| |
| Development and testing |
| ----------------------- |
| |
| SockJS-client needs [node.js](https://nodejs.org/) for running a test |
| server and JavaScript minification. If you want to work on |
| SockJS-client source code, checkout the git repo and follow these |
| steps: |
| |
| cd sockjs-client |
| npm install |
| |
| To generate JavaScript, run: |
| |
| gulp browserify |
| |
| To generate minified JavaScript, run: |
| |
| gulp browserify:min |
| |
| Both commands output into the `build` directory. |
| |
| ### Testing |
| |
| Automated testing provided by: |
| |
| <a href="https://browserstack.com"><img src="img/Browserstack-logo@2x.png" height="50"></a> |
| |
| Once you've compiled the SockJS-client you may want to check if your changes |
| pass all the tests. |
| |
| npm run test:browser_local |
| |
| This will start [karma](https://karma-runner.github.io) and a test support server. |
| |
| Browser Quirks |
| -------------- |
| |
| There are various browser quirks which we don't intend to address: |
| |
| * Pressing ESC in Firefox, before Firefox 20, closes the SockJS connection. For a workaround |
| and discussion see [#18](https://github.com/sockjs/sockjs-client/issues/18). |
| * `jsonp-polling` transport will show a "spinning wheel" (aka. "busy indicator") |
| when sending data. |
| * You can't open more than one SockJS connection to one domain at the |
| same time due to [the browser's limit of concurrent connections](https://stackoverflow.com/questions/985431/max-parallel-http-connections-in-a-browser) |
| (this limit is not counting native WebSocket connections). |
| * Although SockJS is trying to escape any strange Unicode characters |
| (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)) |
| it's advisable to use only valid characters. Using invalid |
| characters is a bit slower, and may not work with SockJS servers |
| that have proper Unicode support. |
| * Having a global function called `onmessage` or such is probably a |
| bad idea, as it could be called by the built-in `postMessage` API. |
| * From SockJS' point of view there is nothing special about |
| SSL/HTTPS. Connecting between unencrypted and encrypted sites |
| should work just fine. |
| * Although SockJS does its best to support both prefix and cookie based |
| sticky sessions, the latter may not work well cross-domain with |
| browsers that don't accept third-party cookies by default (Safari). |
| In order to get around this make sure you're connecting to SockJS |
| from the same parent domain as the main site. For example |
| 'sockjs.a.com' is able to set cookies if you're connecting from |
| 'www.a.com' or 'a.com'. |
| * Trying to connect from secure "https://" to insecure "http://" is |
| not a good idea. The other way around should be fine. |
| * Long polling is known to cause problems on Heroku, but a |
| [workaround for SockJS is available](https://github.com/sockjs/sockjs-node/issues/57#issuecomment-5242187). |
| * SockJS [websocket transport is more stable over SSL](https://github.com/sockjs/sockjs-client/issues/94). If |
| you're a serious SockJS user then consider using SSL |
| ([more info](https://www.ietf.org/mail-archive/web/hybi/current/msg01605.html)). |