sockjs-node

WebSocket emulation - Node.js server

Github stars Tracking Chart

SockJS-node

npm versionDependencies

SockJS for enterprise

Available as part of the Tidelift Subscription.

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.

SockJS family

Work in progress:

⚠️️ ATTENTION This is pre-release documentation. The documentation for the
latest stable release is at: https://github.com/sockjs/sockjs-node/tree/v0.3.19 ️⚠️

What is SockJS?

SockJS is a JavaScript library (for browsers) 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, with WebSockets or without.
This necessitates the use of a server, which this is one version of, for Node.js.

SockJS-node server

SockJS-node is a Node.js server side counterpart of
SockJS-client browser library.

To install sockjs-node run:

npm install sockjs

A simplified echo SockJS server could look more or less like:

const http = require('http');
const sockjs = require('sockjs');

const echo = sockjs.createServer({ prefix:'/echo' });
echo.on('connection', function(conn) {
  conn.on('data', function(message) {
    conn.write(message);
  });
  conn.on('close', function() {});
});

const server = http.createServer();
echo.attach(server);
server.listen(9999, '0.0.0.0');

(Take look at
examples
directory for a complete version.)

Subscribe to
SockJS mailing list for
discussions and support.

SockJS-node API

The API design is based on common Node APIs like the
Streams API or the
Http.Server API.

Server class

SockJS module is generating a Server class, similar to
Node.js http.createServer
module.

const sockjs_server = sockjs.createServer(options);

Where options is a hash which can contain:

Server instance

Once you have create Server instance you can hook it to the
http.Server instance.

var http_server = http.createServer();
sockjs_server.attach(http_server);
http_server.listen(...);

Server instance is an
EventEmitter,
and emits following event:

All http requests that don't go under the path selected by prefix
will remain unanswered and will be passed to previously registered
handlers. You must install your custom http handlers before calling
attach. You can remove the SockJS handler later with detach.

Connection instance

A Connection instance supports
Node Stream API and
has following methods and properties:

A Connection instance emits the following events:

For example:

sockjs_server.on('connection', function(conn) {
  console.log('connection' + conn);
  conn.on('close', function() {
    console.log('close ' + conn);
  });
  conn.on('data', function(message) {
    console.log('message ' + conn, message);
  });
});

Footnote

A fully working echo server does need a bit more boilerplate (to
handle requests unanswered by SockJS), see the
echo example
for a complete code.

Examples

If you want to see samples of running code, take a look at:

Connecting to SockJS-node without the client

Although the main point of SockJS it 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).

Note: This endpoint will not send any heartbeat packets.

Deployment and load balancing

There are two issues that need to be considered when planning a
non-trivial SockJS-node deployment: WebSocket-compatible load balancer
and sticky sessions (aka session affinity).

WebSocket compatible load balancer

Often WebSockets don't play nicely with proxies and load balancers.
Deploying a SockJS server behind Nginx or Apache could be painful.

Fortunately recent versions of an excellent load balancer
HAProxy are able to proxy WebSocket
connections. We propose to put HAProxy as a front line load balancer
and use it to split SockJS traffic from normal HTTP data. Take a look
at the sample
SockJS HAProxy configuration.

The config also shows how to use HAproxy balancing to split traffic
between multiple Node.js servers. You can also do balancing using dns
names.

Sticky sessions

If you plan deploying more than one SockJS server, you must make sure
that all HTTP requests for a single session will hit the same server.
SockJS has two mechanisms that can be useful to achieve that:

  • Urls are prefixed with server and session id numbers, like:
    /resource/<server_number>/<session_id>/transport. This is
    useful for load balancers that support prefix-based affinity
    (HAProxy does).
  • JSESSIONID cookie is being set by SockJS-node. Many load
    balancers turn on sticky sessions if that cookie is set. This
    technique is derived from Java applications, where sticky sessions
    are often necessary. HAProxy does support this method, as well as
    some hosting providers, for example CloudFoundry. In order to
    enable this method on the client side, please supply a
    cookie:true option to SockJS constructor.

Development and testing

If you want to work on SockJS-node source code, you need to clone the
git repo and follow these steps. First you need to install
dependencies:

cd sockjs-node
npm install

If compilation succeeds you may want to test if your changes pass all
the tests. Currently, there are two separate test suites.

SockJS-protocol Python tests

To run it run something like:

./scripts/test.sh

For details see
SockJS-protocol README.

SockJS-client Karma tests

To run it run something like:

cd sockjs-client
npm run test:browser_local

For details see
SockJS-client README.

Various issues and design considerations

Authorisation

SockJS-node does not expose cookies to the application. This is done
deliberately as using cookie-based authorisation with SockJS simply
doesn't make sense and will lead to security issues.

Cookies are a contract between a browser and an http server, and are
identified by a domain name. If a browser has a cookie set for
particular domain, it will pass it as a part of all http requests to
the host. But to get various transports working, SockJS uses a middleman

  • an iframe hosted from target SockJS domain. That means the server
    will receive requests from the iframe, and not from the real
    domain. The domain of an iframe is the same as the SockJS domain. The
    problem is that any website can embed the iframe and communicate with
    it - and request establishing SockJS connection. Using cookies for
    authorisation in this scenario will result in granting full access to
    SockJS communication with your website from any website. This is a
    classic CSRF attack.

Basically - cookies are not suited for SockJS model. If you want to
authorise a session - provide a unique token on a page, send it as a
first thing over SockJS connection and validate it on the server
side. In essence, this is how cookies work.

Deploying SockJS on Heroku

Long polling is known to cause problems on Heroku, but
workaround for SockJS is available.

Main metrics

Overview
Name With Ownersockjs/sockjs-node
Primary LanguageJavaScript
Program languageJavaScript (Language Count: 2)
Platform
License:MIT License
所有者活动
Created At2011-07-22 14:22:50
Pushed At2024-12-24 10:08:22
Last Commit At2020-06-08 00:00:29
Release Count36
Last Release Namev0.3.24 (Posted on 2021-12-02 17:50:38)
First Release Namev0.0.0-rc1 (Posted on 2011-08-11 17:22:35)
用户参与
Stargazers Count2.1k
Watchers Count60
Fork Count307
Commits Count556
Has Issues Enabled
Issues Count208
Issue Open Count15
Pull Requests Count58
Pull Requests Open Count4
Pull Requests Close Count35
项目设置
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private