19241cb1f5c427dc689cd9d454a4a28cda91bb3403e2d8fe97487f90613cb1e62249678a611f19a99ca05795133856c03b1f66564798989420544f48284ef3 17 KB

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