| [9af201e] | 1 | [](http://badge.fury.io/js/sockjs)
|
|---|
| 2 |
|
|---|
| 3 | SockJS family:
|
|---|
| 4 |
|
|---|
| 5 | * [SockJS-client](https://github.com/sockjs/sockjs-client) JavaScript client library
|
|---|
| 6 | * [SockJS-node](https://github.com/sockjs/sockjs-node) Node.js server
|
|---|
| 7 | * [SockJS-erlang](https://github.com/sockjs/sockjs-erlang) Erlang server
|
|---|
| 8 | * [SockJS-tornado](https://github.com/MrJoes/sockjs-tornado) Python/Tornado server
|
|---|
| 9 | * [vert.x](https://github.com/eclipse/vert.x) Java/vert.x server
|
|---|
| 10 |
|
|---|
| 11 | Work in progress:
|
|---|
| 12 |
|
|---|
| 13 | * [SockJS-ruby](https://github.com/nyarly/sockjs-ruby)
|
|---|
| 14 | * [SockJS-netty](https://github.com/cgbystrom/sockjs-netty)
|
|---|
| 15 | * [SockJS-gevent](https://github.com/sdiehl/sockjs-gevent) ([and a fork](https://github.com/njoyce/sockjs-gevent))
|
|---|
| 16 | * [pyramid-SockJS](https://github.com/fafhrd91/pyramid_sockjs)
|
|---|
| 17 | * [wildcloud-websockets](https://github.com/wildcloud/wildcloud-websockets)
|
|---|
| 18 | * [SockJS-cyclone](https://github.com/flaviogrossi/sockjs-cyclone)
|
|---|
| 19 | * [SockJS-twisted](https://github.com/Fugiman/sockjs-twisted/)
|
|---|
| 20 | * [wai-SockJS](https://github.com/Palmik/wai-sockjs)
|
|---|
| 21 | * [SockJS-perl](https://github.com/vti/sockjs-perl)
|
|---|
| 22 | * [SockJS-go](https://github.com/igm/sockjs-go/)
|
|---|
| 23 |
|
|---|
| 24 | What is SockJS?
|
|---|
| 25 | ===============
|
|---|
| 26 |
|
|---|
| 27 | SockJS is a JavaScript library (for browsers) that provides a WebSocket-like
|
|---|
| 28 | object. SockJS gives you a coherent, cross-browser, Javascript API
|
|---|
| 29 | which creates a low latency, full duplex, cross-domain communication
|
|---|
| 30 | channel between the browser and the web server, with WebSockets or without.
|
|---|
| 31 | This necessitates the use of a server, which this is one version of, for Node.js.
|
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 | SockJS-node server
|
|---|
| 35 | ==================
|
|---|
| 36 |
|
|---|
| 37 | SockJS-node is a Node.js server side counterpart of
|
|---|
| 38 | [SockJS-client browser library](https://github.com/sockjs/sockjs-client)
|
|---|
| 39 | written in CoffeeScript.
|
|---|
| 40 |
|
|---|
| 41 | To install `sockjs-node` run:
|
|---|
| 42 |
|
|---|
| 43 | npm install sockjs
|
|---|
| 44 |
|
|---|
| 45 | A simplified echo SockJS server could look more or less like:
|
|---|
| 46 |
|
|---|
| 47 | ```javascript
|
|---|
| 48 | var http = require('http');
|
|---|
| 49 | var sockjs = require('sockjs');
|
|---|
| 50 |
|
|---|
| 51 | var echo = sockjs.createServer();
|
|---|
| 52 | echo.on('connection', function(conn) {
|
|---|
| 53 | conn.on('data', function(message) {
|
|---|
| 54 | conn.write(message);
|
|---|
| 55 | });
|
|---|
| 56 | conn.on('close', function() {});
|
|---|
| 57 | });
|
|---|
| 58 |
|
|---|
| 59 | var server = http.createServer();
|
|---|
| 60 | echo.installHandlers(server, {prefix:'/echo'});
|
|---|
| 61 | server.listen(9999, '0.0.0.0');
|
|---|
| 62 | ```
|
|---|
| 63 |
|
|---|
| 64 | (Take look at
|
|---|
| 65 | [examples](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
|
|---|
| 66 | directory for a complete version.)
|
|---|
| 67 |
|
|---|
| 68 | Subscribe to
|
|---|
| 69 | [SockJS mailing list](https://groups.google.com/forum/#!forum/sockjs) for
|
|---|
| 70 | discussions and support.
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 | SockJS-node API
|
|---|
| 74 | ---------------
|
|---|
| 75 |
|
|---|
| 76 | The API design is based on common Node APIs like the
|
|---|
| 77 | [Streams API](http://nodejs.org/docs/v0.5.8/api/streams.html) or the
|
|---|
| 78 | [Http.Server API](http://nodejs.org/docs/v0.5.8/api/http.html#http.Server).
|
|---|
| 79 |
|
|---|
| 80 | ### Server class
|
|---|
| 81 |
|
|---|
| 82 | SockJS module is generating a `Server` class, similar to
|
|---|
| 83 | [Node.js http.createServer](http://nodejs.org/docs/v0.5.8/api/http.html#http.createServer)
|
|---|
| 84 | module.
|
|---|
| 85 |
|
|---|
| 86 | ```javascript
|
|---|
| 87 | var sockjs_server = sockjs.createServer(options);
|
|---|
| 88 | ```
|
|---|
| 89 |
|
|---|
| 90 | Where `options` is a hash which can contain:
|
|---|
| 91 |
|
|---|
| 92 | <dl>
|
|---|
| 93 | <dt>sockjs_url (string)</dt>
|
|---|
| 94 | <dd>Transports which don't support cross-domain communication natively
|
|---|
| 95 | ('eventsource' to name one) use an iframe trick. A simple page is
|
|---|
| 96 | served from the SockJS server (using its foreign domain) and is
|
|---|
| 97 | placed in an invisible iframe. Code run from this iframe doesn't
|
|---|
| 98 | need to worry about cross-domain issues, as it's being run from
|
|---|
| 99 | domain local to the SockJS server. This iframe also does need to
|
|---|
| 100 | load SockJS javascript client library, and this option lets you specify
|
|---|
| 101 | its url (if you're unsure, point it to
|
|---|
| 102 | <a href="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js">
|
|---|
| 103 | the latest minified SockJS client release</a>, this is the default).
|
|---|
| 104 | You must explicitly specify this url on the server side for security
|
|---|
| 105 | reasons - we don't want the possibility of running any foreign
|
|---|
| 106 | javascript within the SockJS domain (aka cross site scripting attack).
|
|---|
| 107 | Also, sockjs javascript library is probably already cached by the
|
|---|
| 108 | browser - it makes sense to reuse the sockjs url you're using in
|
|---|
| 109 | normally.</dd>
|
|---|
| 110 |
|
|---|
| 111 | <dt>prefix (string regex)</dt>
|
|---|
| 112 | <dd>A url prefix for the server. All http requests which paths begins
|
|---|
| 113 | with selected prefix will be handled by SockJS. All other requests
|
|---|
| 114 | will be passed through, to previously registered handlers.</dd>
|
|---|
| 115 |
|
|---|
| 116 | <dt>response_limit (integer)</dt>
|
|---|
| 117 | <dd>Most streaming transports save responses on the client side and
|
|---|
| 118 | don't free memory used by delivered messages. Such transports need
|
|---|
| 119 | to be garbage-collected once in a while. `response_limit` sets
|
|---|
| 120 | a minimum number of bytes that can be send over a single http streaming
|
|---|
| 121 | request before it will be closed. After that client needs to open
|
|---|
| 122 | new request. Setting this value to one effectively disables
|
|---|
| 123 | streaming and will make streaming transports to behave like polling
|
|---|
| 124 | transports. The default value is 128K.</dd>
|
|---|
| 125 |
|
|---|
| 126 | <dt>websocket (boolean)</dt>
|
|---|
| 127 | <dd>Some load balancers don't support websockets. This option can be used
|
|---|
| 128 | to disable websockets support by the server. By default websockets are
|
|---|
| 129 | enabled.</dd>
|
|---|
| 130 |
|
|---|
| 131 | <dt>jsessionid (boolean or function)</dt>
|
|---|
| 132 | <dd>Some hosting providers enable sticky sessions only to requests that
|
|---|
| 133 | have JSESSIONID cookie set. This setting controls if the server should
|
|---|
| 134 | set this cookie to a dummy value. By default setting JSESSIONID cookie
|
|---|
| 135 | is disabled. More sophisticated behaviour can be achieved by supplying
|
|---|
| 136 | a function.</dd>
|
|---|
| 137 |
|
|---|
| 138 | <dt>log (function(severity, message))</dt>
|
|---|
| 139 | <dd>It's quite useful, especially for debugging, to see some messages
|
|---|
| 140 | printed by a SockJS-node library. This is done using this `log`
|
|---|
| 141 | function, which is by default set to `console.log`. If this
|
|---|
| 142 | behaviour annoys you for some reason, override `log` setting with a
|
|---|
| 143 | custom handler. The following `severities` are used: `debug`
|
|---|
| 144 | (miscellaneous logs), `info` (requests logs), `error` (serious
|
|---|
| 145 | errors, consider filing an issue).</dd>
|
|---|
| 146 |
|
|---|
| 147 | <dt>heartbeat_delay (milliseconds)</dt>
|
|---|
| 148 | <dd>In order to keep proxies and load balancers from closing long
|
|---|
| 149 | running http requests we need to pretend that the connection is
|
|---|
| 150 | active and send a heartbeat packet once in a while. This setting
|
|---|
| 151 | controls how often this is done. By default a heartbeat packet is
|
|---|
| 152 | sent every 25 seconds. </dd>
|
|---|
| 153 |
|
|---|
| 154 | <dt>disconnect_delay (milliseconds)</dt>
|
|---|
| 155 | <dd>The server sends a `close` event when a client receiving
|
|---|
| 156 | connection have not been seen for a while. This delay is configured
|
|---|
| 157 | by this setting. By default the `close` event will be emitted when a
|
|---|
| 158 | receiving connection wasn't seen for 5 seconds. </dd>
|
|---|
| 159 |
|
|---|
| 160 | <dt>disable_cors (boolean)</dt>
|
|---|
| 161 | <dd>Enabling this option will prevent
|
|---|
| 162 | <a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing">CORS</a>
|
|---|
| 163 | headers from being included in the HTTP response. Can be used when the
|
|---|
| 164 | sockjs client is known to be connecting from the same origin as the
|
|---|
| 165 | sockjs server.</dd>
|
|---|
| 166 | </dl>
|
|---|
| 167 |
|
|---|
| 168 |
|
|---|
| 169 | ### Server instance
|
|---|
| 170 |
|
|---|
| 171 | Once you have create `Server` instance you can hook it to the
|
|---|
| 172 | [http.Server instance](http://nodejs.org/docs/v0.5.8/api/http.html#http.createServer).
|
|---|
| 173 |
|
|---|
| 174 | ```javascript
|
|---|
| 175 | var http_server = http.createServer();
|
|---|
| 176 | sockjs_server.installHandlers(http_server, options);
|
|---|
| 177 | http_server.listen(...);
|
|---|
| 178 | ```
|
|---|
| 179 |
|
|---|
| 180 | Where `options` can overshadow options given when creating `Server`
|
|---|
| 181 | instance.
|
|---|
| 182 |
|
|---|
| 183 | `Server` instance is an
|
|---|
| 184 | [EventEmitter](http://nodejs.org/docs/v0.4.10/api/events.html#events.EventEmitter),
|
|---|
| 185 | and emits following event:
|
|---|
| 186 |
|
|---|
| 187 | <dl>
|
|---|
| 188 | <dt>Event: connection (connection)</dt>
|
|---|
| 189 | <dd>A new connection has been successfully opened.</dd>
|
|---|
| 190 | </dl>
|
|---|
| 191 |
|
|---|
| 192 | All http requests that don't go under the path selected by `prefix`
|
|---|
| 193 | will remain unanswered and will be passed to previously registered
|
|---|
| 194 | handlers. You must install your custom http handlers before calling
|
|---|
| 195 | `installHandlers`.
|
|---|
| 196 |
|
|---|
| 197 | ### Connection instance
|
|---|
| 198 |
|
|---|
| 199 | A `Connection` instance supports
|
|---|
| 200 | [Node Stream API](http://nodejs.org/docs/v0.5.8/api/streams.html) and
|
|---|
| 201 | has following methods and properties:
|
|---|
| 202 |
|
|---|
| 203 | <dl>
|
|---|
| 204 | <dt>Property: readable (boolean)</dt>
|
|---|
| 205 | <dd>Is the stream readable?</dd>
|
|---|
| 206 |
|
|---|
| 207 | <dt>Property: writable (boolean)</dt>
|
|---|
| 208 | <dd>Is the stream writable?</dd>
|
|---|
| 209 |
|
|---|
| 210 | <dt>Property: remoteAddress (string)</dt>
|
|---|
| 211 | <dd>Last known IP address of the client.</dd>
|
|---|
| 212 |
|
|---|
| 213 | <dt>Property: remotePort (number)</dt>
|
|---|
| 214 | <dd>Last known port number of the client.</dd>
|
|---|
| 215 |
|
|---|
| 216 | <dt>Property: address (object)</dt>
|
|---|
| 217 | <dd>Hash with 'address' and 'port' fields.</dd>
|
|---|
| 218 |
|
|---|
| 219 | <dt>Property: headers (object)</dt>
|
|---|
| 220 | <dd>Hash containing various headers copied from last receiving request
|
|---|
| 221 | on that connection. Exposed headers include: `origin`, `referer`
|
|---|
| 222 | and `x-forwarded-for` (and friends). We explicitly do not grant
|
|---|
| 223 | access to `cookie` header, as using it may easily lead to security
|
|---|
| 224 | issues (for details read the section "Authorisation").</dd>
|
|---|
| 225 |
|
|---|
| 226 | <dt>Property: url (string)</dt>
|
|---|
| 227 | <dd><a href="http://nodejs.org/docs/v0.4.10/api/http.html#request.url">Url</a>
|
|---|
| 228 | property copied from last request.</dd>
|
|---|
| 229 |
|
|---|
| 230 | <dt>Property: pathname (string)</dt>
|
|---|
| 231 | <dd>`pathname` from parsed url, for convenience.</dd>
|
|---|
| 232 |
|
|---|
| 233 | <dt>Property: prefix (string)</dt>
|
|---|
| 234 | <dd>Prefix of the url on which the request was handled.</dd>
|
|---|
| 235 |
|
|---|
| 236 | <dt>Property: protocol (string)</dt>
|
|---|
| 237 | <dd>Protocol used by the connection. Keep in mind that some protocols
|
|---|
| 238 | are indistinguishable - for example "xhr-polling" and "xdr-polling".</dd>
|
|---|
| 239 |
|
|---|
| 240 | <dt>Property: readyState (integer)</dt>
|
|---|
| 241 | <dd>Current state of the connection:
|
|---|
| 242 | 0-connecting, 1-open, 2-closing, 3-closed.</dd>
|
|---|
| 243 |
|
|---|
| 244 | <dt>write(message)</dt>
|
|---|
| 245 | <dd>Sends a message over opened connection. A message must be a
|
|---|
| 246 | non-empty string. It's illegal to send a message after the connection was
|
|---|
| 247 | closed (either after 'close' or 'end' method or 'close' event).</dd>
|
|---|
| 248 |
|
|---|
| 249 | <dt>close([code], [reason])</dt>
|
|---|
| 250 | <dd>Asks the remote client to disconnect. 'code' and 'reason'
|
|---|
| 251 | parameters are optional and can be used to share the reason of
|
|---|
| 252 | disconnection.</dd>
|
|---|
| 253 |
|
|---|
| 254 | <dt>end()</dt>
|
|---|
| 255 | <dd>Asks the remote client to disconnect with default 'code' and
|
|---|
| 256 | 'reason' values.</dd>
|
|---|
| 257 |
|
|---|
| 258 | </dl>
|
|---|
| 259 |
|
|---|
| 260 | A `Connection` instance emits the following events:
|
|---|
| 261 |
|
|---|
| 262 | <dl>
|
|---|
| 263 | <dt>Event: data (message)</dt>
|
|---|
| 264 | <dd>A message arrived on the connection. Message is a unicode
|
|---|
| 265 | string.</dd>
|
|---|
| 266 |
|
|---|
| 267 | <dt>Event: close ()</dt>
|
|---|
| 268 | <dd>Connection was closed. This event is triggered exactly once for
|
|---|
| 269 | every connection.</dd>
|
|---|
| 270 | </dl>
|
|---|
| 271 |
|
|---|
| 272 | For example:
|
|---|
| 273 |
|
|---|
| 274 | ```javascript
|
|---|
| 275 | sockjs_server.on('connection', function(conn) {
|
|---|
| 276 | console.log('connection' + conn);
|
|---|
| 277 | conn.on('close', function() {
|
|---|
| 278 | console.log('close ' + conn);
|
|---|
| 279 | });
|
|---|
| 280 | conn.on('data', function(message) {
|
|---|
| 281 | console.log('message ' + conn,
|
|---|
| 282 | message);
|
|---|
| 283 | });
|
|---|
| 284 | });
|
|---|
| 285 | ```
|
|---|
| 286 |
|
|---|
| 287 | ### Footnote
|
|---|
| 288 |
|
|---|
| 289 | A fully working echo server does need a bit more boilerplate (to
|
|---|
| 290 | handle requests unanswered by SockJS), see the
|
|---|
| 291 | [`echo` example](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
|
|---|
| 292 | for a complete code.
|
|---|
| 293 |
|
|---|
| 294 | ### Examples
|
|---|
| 295 |
|
|---|
| 296 | If you want to see samples of running code, take a look at:
|
|---|
| 297 |
|
|---|
| 298 | * [./examples/echo](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
|
|---|
| 299 | directory, which contains a full example of a echo server.
|
|---|
| 300 | * [./examples/test_server](https://github.com/sockjs/sockjs-node/tree/master/examples/test_server) a standard SockJS test server.
|
|---|
| 301 |
|
|---|
| 302 |
|
|---|
| 303 | Connecting to SockJS-node without the client
|
|---|
| 304 | --------------------------------------------
|
|---|
| 305 |
|
|---|
| 306 | Although the main point of SockJS it to enable browser-to-server
|
|---|
| 307 | connectivity, it is possible to connect to SockJS from an external
|
|---|
| 308 | application. Any SockJS server complying with 0.3 protocol does
|
|---|
| 309 | support a raw WebSocket url. The raw WebSocket url for the test server
|
|---|
| 310 | looks like:
|
|---|
| 311 |
|
|---|
| 312 | * ws://localhost:8081/echo/websocket
|
|---|
| 313 |
|
|---|
| 314 | You can connect any WebSocket RFC 6455 compliant WebSocket client to
|
|---|
| 315 | this url. This can be a command line client, external application,
|
|---|
| 316 | third party code or even a browser (though I don't know why you would
|
|---|
| 317 | want to do so).
|
|---|
| 318 |
|
|---|
| 319 | Note: This endpoint will *not send any heartbeat packets*.
|
|---|
| 320 |
|
|---|
| 321 |
|
|---|
| 322 | Deployment and load balancing
|
|---|
| 323 | -----------------------------
|
|---|
| 324 |
|
|---|
| 325 | There are two issues that need to be considered when planning a
|
|---|
| 326 | non-trivial SockJS-node deployment: WebSocket-compatible load balancer
|
|---|
| 327 | and sticky sessions (aka session affinity).
|
|---|
| 328 |
|
|---|
| 329 | ### WebSocket compatible load balancer
|
|---|
| 330 |
|
|---|
| 331 | Often WebSockets don't play nicely with proxies and load balancers.
|
|---|
| 332 | Deploying a SockJS server behind Nginx or Apache could be painful.
|
|---|
| 333 |
|
|---|
| 334 | Fortunately recent versions of an excellent load balancer
|
|---|
| 335 | [HAProxy](http://haproxy.1wt.eu/) are able to proxy WebSocket
|
|---|
| 336 | connections. We propose to put HAProxy as a front line load balancer
|
|---|
| 337 | and use it to split SockJS traffic from normal HTTP data. Take a look
|
|---|
| 338 | at the sample
|
|---|
| 339 | [SockJS HAProxy configuration](https://github.com/sockjs/sockjs-node/blob/master/examples/haproxy.cfg).
|
|---|
| 340 |
|
|---|
| 341 | The config also shows how to use HAproxy balancing to split traffic
|
|---|
| 342 | between multiple Node.js servers. You can also do balancing using dns
|
|---|
| 343 | names.
|
|---|
| 344 |
|
|---|
| 345 | ### Sticky sessions
|
|---|
| 346 |
|
|---|
| 347 | If you plan deploying more than one SockJS server, you must make sure
|
|---|
| 348 | that all HTTP requests for a single session will hit the same server.
|
|---|
| 349 | SockJS has two mechanisms that can be useful to achieve that:
|
|---|
| 350 |
|
|---|
| 351 | * Urls are prefixed with server and session id numbers, like:
|
|---|
| 352 | `/resource/<server_number>/<session_id>/transport`. This is
|
|---|
| 353 | useful for load balancers that support prefix-based affinity
|
|---|
| 354 | (HAProxy does).
|
|---|
| 355 | * `JSESSIONID` cookie is being set by SockJS-node. Many load
|
|---|
| 356 | balancers turn on sticky sessions if that cookie is set. This
|
|---|
| 357 | technique is derived from Java applications, where sticky sessions
|
|---|
| 358 | are often necessary. HAProxy does support this method, as well as
|
|---|
| 359 | some hosting providers, for example CloudFoundry. In order to
|
|---|
| 360 | enable this method on the client side, please supply a
|
|---|
| 361 | `cookie:true` option to SockJS constructor.
|
|---|
| 362 |
|
|---|
| 363 |
|
|---|
| 364 | Development and testing
|
|---|
| 365 | -----------------------
|
|---|
| 366 |
|
|---|
| 367 | If you want to work on SockJS-node source code, you need to clone the
|
|---|
| 368 | git repo and follow these steps. First you need to install
|
|---|
| 369 | dependencies:
|
|---|
| 370 |
|
|---|
| 371 | cd sockjs-node
|
|---|
| 372 | npm install
|
|---|
| 373 | npm install --dev
|
|---|
| 374 | ln -s .. node_modules/sockjs
|
|---|
| 375 |
|
|---|
| 376 | You're ready to compile CoffeeScript:
|
|---|
| 377 |
|
|---|
| 378 | make build
|
|---|
| 379 |
|
|---|
| 380 | If compilation succeeds you may want to test if your changes pass all
|
|---|
| 381 | the tests. Currently, there are two separate test suites. For both of
|
|---|
| 382 | them you need to start a SockJS-node test server (by default listening
|
|---|
| 383 | on port 8081):
|
|---|
| 384 |
|
|---|
| 385 | make test_server
|
|---|
| 386 |
|
|---|
| 387 | ### SockJS-protocol Python tests
|
|---|
| 388 |
|
|---|
| 389 | To run it run something like:
|
|---|
| 390 |
|
|---|
| 391 | cd sockjs-protocol
|
|---|
| 392 | make test_deps
|
|---|
| 393 | ./venv/bin/python sockjs-protocol.py
|
|---|
| 394 |
|
|---|
| 395 | For details see
|
|---|
| 396 | [SockJS-protocol README](https://github.com/sockjs/sockjs-protocol#readme).
|
|---|
| 397 |
|
|---|
| 398 | ### SockJS-client QUnit tests
|
|---|
| 399 |
|
|---|
| 400 | You need to start a second web server (by default listening on 8080)
|
|---|
| 401 | that is serving various static html and javascript files:
|
|---|
| 402 |
|
|---|
| 403 | cd sockjs-client
|
|---|
| 404 | make test
|
|---|
| 405 |
|
|---|
| 406 | At that point you should have two web servers running: sockjs-node on
|
|---|
| 407 | 8081 and sockjs-client on 8080. When you open the browser on
|
|---|
| 408 | [http://localhost:8080/](http://localhost:8080/) you should be able
|
|---|
| 409 | run the QUnit tests against your sockjs-node server.
|
|---|
| 410 |
|
|---|
| 411 | For details see
|
|---|
| 412 | [SockJS-client README](https://github.com/sockjs/sockjs-client#readme).
|
|---|
| 413 |
|
|---|
| 414 | Additionally, if you're doing more serious development consider using
|
|---|
| 415 | `make serve`, which will automatically the server when you modify the
|
|---|
| 416 | source code.
|
|---|
| 417 |
|
|---|
| 418 |
|
|---|
| 419 | Various issues and design considerations
|
|---|
| 420 | ----------------------------------------
|
|---|
| 421 |
|
|---|
| 422 | ### Authorisation
|
|---|
| 423 |
|
|---|
| 424 | SockJS-node does not expose cookies to the application. This is done
|
|---|
| 425 | deliberately as using cookie-based authorisation with SockJS simply
|
|---|
| 426 | doesn't make sense and will lead to security issues.
|
|---|
| 427 |
|
|---|
| 428 | Cookies are a contract between a browser and an http server, and are
|
|---|
| 429 | identified by a domain name. If a browser has a cookie set for
|
|---|
| 430 | particular domain, it will pass it as a part of all http requests to
|
|---|
| 431 | the host. But to get various transports working, SockJS uses a middleman
|
|---|
| 432 | - an iframe hosted from target SockJS domain. That means the server
|
|---|
| 433 | will receive requests from the iframe, and not from the real
|
|---|
| 434 | domain. The domain of an iframe is the same as the SockJS domain. The
|
|---|
| 435 | problem is that any website can embed the iframe and communicate with
|
|---|
| 436 | it - and request establishing SockJS connection. Using cookies for
|
|---|
| 437 | authorisation in this scenario will result in granting full access to
|
|---|
| 438 | SockJS communication with your website from any website. This is a
|
|---|
| 439 | classic CSRF attack.
|
|---|
| 440 |
|
|---|
| 441 | Basically - cookies are not suited for SockJS model. If you want to
|
|---|
| 442 | authorise a session - provide a unique token on a page, send it as a
|
|---|
| 443 | first thing over SockJS connection and validate it on the server
|
|---|
| 444 | side. In essence, this is how cookies work.
|
|---|
| 445 |
|
|---|
| 446 |
|
|---|
| 447 | ### Deploying SockJS on Heroku
|
|---|
| 448 |
|
|---|
| 449 | Long polling is known to cause problems on Heroku, but
|
|---|
| 450 | [workaround for SockJS is available](https://github.com/sockjs/sockjs-node/issues/57#issuecomment-5242187).
|
|---|