Convert Figma logo to code with AI

sockjs logosockjs-node

WebSocket emulation - Node.js server

2,093
309
2,093
19

Top Related Projects

4,391

Simple pub/sub messaging for the web

61,034

Realtime application framework (Node.JS server)

4,472

:zap: Primus, the creator god of the transformers & an abstraction layer for real-time to prevent module lock-in.

21,639

Simple to use, blazing fast and thoroughly tested WebSocket client and server for Node.js

Simple, secure & standards compliant web server for the most demanding of applications

A WebSocket Implementation for Node.JS (Draft -08 through the final RFC 6455)

Quick Overview

SockJS-node is a server-side component of the SockJS family, providing a WebSocket-like object in Node.js. It's designed to work with various browsers and environments, offering a consistent interface for real-time web applications. SockJS-node is particularly useful for creating robust, cross-browser compatible WebSocket connections.

Pros

  • Cross-browser compatibility, including support for older browsers
  • Fallback mechanisms for environments where WebSockets are not available
  • Easy integration with existing Node.js applications
  • Supports various transport protocols for maximum flexibility

Cons

  • May introduce additional overhead compared to native WebSockets
  • Requires client-side SockJS library for full functionality
  • Learning curve for developers new to WebSocket-like technologies
  • Maintenance and updates may lag behind newer WebSocket implementations

Code Examples

  1. Creating a SockJS server:
const http = require('http');
const sockjs = require('sockjs');

const echo = sockjs.createServer();
echo.on('connection', (conn) => {
    conn.on('data', (message) => {
        conn.write(message);
    });
});

const server = http.createServer();
echo.attach(server);
server.listen(9999, '0.0.0.0');
  1. Handling client connections:
const sockjs = require('sockjs');

const sockServer = sockjs.createServer();
sockServer.on('connection', (conn) => {
    console.log('New connection');
    conn.on('close', () => {
        console.log('Connection closed');
    });
});
  1. Sending messages to clients:
const sockjs = require('sockjs');

const sockServer = sockjs.createServer();
sockServer.on('connection', (conn) => {
    setInterval(() => {
        conn.write('Server time: ' + new Date());
    }, 1000);
});

Getting Started

To use SockJS-node in your project:

  1. Install the package:

    npm install sockjs
    
  2. Create a basic server:

    const http = require('http');
    const sockjs = require('sockjs');
    
    const sockServer = sockjs.createServer();
    sockServer.on('connection', (conn) => {
        conn.on('data', (message) => {
            console.log('Received:', message);
            conn.write('Echo: ' + message);
        });
    });
    
    const server = http.createServer();
    sockServer.attach(server);
    server.listen(3000, () => {
        console.log('SockJS server listening on port 3000');
    });
    
  3. Implement client-side code using the SockJS client library.

Competitor Comparisons

4,391

Simple pub/sub messaging for the web

Pros of Faye

  • Supports both server-side and client-side implementations
  • Provides a simple publish-subscribe messaging pattern
  • Offers built-in support for multiple transport mechanisms (WebSocket, EventSource, long-polling)

Cons of Faye

  • Less actively maintained compared to SockJS-node
  • May have higher latency for some use cases
  • Limited cross-browser compatibility for older browsers

Code Comparison

SockJS-node:

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

const echo = sockjs.createServer();
echo.on('connection', (conn) => {
    conn.on('data', (message) => {
        conn.write(message);
    });
});

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

Faye:

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

const server = http.createServer();
const bayeux = new faye.NodeAdapter({mount: '/faye', timeout: 45});

bayeux.attach(server);
server.listen(8000);

Both libraries provide real-time communication capabilities, but SockJS-node focuses on providing a WebSocket-like API with fallbacks, while Faye implements a publish-subscribe messaging system. SockJS-node may be more suitable for direct socket-like communication, whereas Faye excels in scenarios requiring message broadcasting and subscription management.

61,034

Realtime application framework (Node.JS server)

Pros of Socket.IO

  • Built-in support for multiple transports (WebSocket, polling, etc.)
  • Automatic reconnection and fallback mechanisms
  • Rich set of additional features like rooms and namespaces

Cons of Socket.IO

  • Larger library size and potential overhead
  • Custom protocol, not fully compatible with raw WebSocket implementations
  • Steeper learning curve for advanced features

Code Comparison

Socket.IO server setup:

const io = require('socket.io')(3000);
io.on('connection', (socket) => {
  console.log('A user connected');
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });
});

SockJS server setup:

const http = require('http');
const sockjs = require('sockjs');
const echo = sockjs.createServer();
echo.on('connection', (conn) => {
  conn.on('data', (message) => {
    conn.write(message);
  });
});
const server = http.createServer();
echo.attach(server);
server.listen(3000);

Both libraries provide real-time, bidirectional communication between clients and servers. Socket.IO offers more built-in features and abstractions, while SockJS focuses on providing a WebSocket-like API with fallback options. The choice between them depends on specific project requirements, desired features, and compatibility needs.

4,472

:zap: Primus, the creator god of the transformers & an abstraction layer for real-time to prevent module lock-in.

Pros of Primus

  • Supports multiple transport protocols (WebSockets, Engine.IO, SockJS, etc.)
  • Provides a unified API across different transports
  • Offers built-in plugins for additional functionality

Cons of Primus

  • Steeper learning curve due to its abstraction layer
  • Potentially larger bundle size when including multiple transports

Code Comparison

SockJS-node:

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

const echo = sockjs.createServer();
echo.on('connection', (conn) => {
    conn.on('data', (message) => {
        conn.write(message);
    });
});

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

Primus:

const Primus = require('primus');
const http = require('http');

const server = http.createServer();
const primus = new Primus(server, { transformer: 'websockets' });

primus.on('connection', (spark) => {
    spark.on('data', (data) => {
        spark.write(data);
    });
});

server.listen(9999);

Summary

SockJS-node is focused on providing a WebSocket-like API with fallbacks, while Primus offers a more flexible approach with multiple transport options. Primus provides a unified API and plugin system, but may have a steeper learning curve. SockJS-node is simpler to set up for basic WebSocket functionality, while Primus offers more extensibility for complex use cases.

21,639

Simple to use, blazing fast and thoroughly tested WebSocket client and server for Node.js

Pros of ws

  • Lightweight and fast, with minimal overhead
  • Supports both server and client-side WebSocket implementations
  • Extensive test coverage and active maintenance

Cons of ws

  • Limited fallback options for older browsers or restrictive networks
  • Lacks built-in support for session management and routing

Code Comparison

ws:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
});

SockJS:

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

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

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

Key Differences

  • SockJS provides fallback options for environments where WebSockets are not supported, while ws focuses solely on WebSocket implementation.
  • ws offers a more lightweight solution, whereas SockJS includes additional features for compatibility and abstraction.
  • SockJS aims to provide a consistent API across different transport mechanisms, while ws is specifically designed for WebSocket communication.

Both libraries have their strengths, and the choice between them depends on specific project requirements, such as browser compatibility needs and desired feature set.

Simple, secure & standards compliant web server for the most demanding of applications

Pros of uWebSockets

  • Significantly higher performance and lower latency
  • Lower memory footprint and CPU usage
  • Support for both WebSocket and HTTP protocols

Cons of uWebSockets

  • Less mature ecosystem and community support
  • Steeper learning curve for developers
  • Limited compatibility with some Node.js-specific features

Code Comparison

SockJS-node:

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

const echo = sockjs.createServer();
echo.on('connection', (conn) => {
    conn.on('data', (message) => {
        conn.write(message);
    });
});

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

uWebSockets:

#include <uwebsockets/App.h>

int main() {
    uWS::App().ws<PerSocketData>("/*", {
        .message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {
            ws->send(message, opCode);
        }
    }).listen(9999, [](auto *listen_socket) {
        if (listen_socket) {
            std::cout << "Listening on port " << 9999 << std::endl;
        }
    }).run();
}

Both libraries provide WebSocket functionality, but uWebSockets offers higher performance at the cost of a more complex setup and less Node.js integration. SockJS-node is easier to use within a Node.js environment and provides better fallback options for browsers that don't support WebSockets.

A WebSocket Implementation for Node.JS (Draft -08 through the final RFC 6455)

Pros of WebSocket-Node

  • Native WebSocket implementation, providing better performance for pure WebSocket connections
  • Supports both server and client-side WebSocket functionality
  • More extensive documentation and examples

Cons of WebSocket-Node

  • Limited fallback options for browsers without WebSocket support
  • Less abstraction for handling different transport methods
  • May require additional setup for cross-browser compatibility

Code Comparison

WebSocket-Node:

const WebSocketServer = require('websocket').server;
const server = new WebSocketServer({
  httpServer: httpServer,
  autoAcceptConnections: false
});

SockJS-node:

const sockjs = require('sockjs');
const sockjsServer = sockjs.createServer();
sockjsServer.on('connection', function(conn) {
  conn.on('data', function(message) {
    // Handle incoming messages
  });
});

Summary

WebSocket-Node is a robust native WebSocket implementation offering better performance for WebSocket-supported environments. It provides both server and client-side functionality with comprehensive documentation. However, it lacks built-in fallback options for older browsers and may require additional setup for cross-browser compatibility.

SockJS-node, on the other hand, offers a more abstracted approach with various transport methods and fallback options, making it easier to support a wider range of browsers and environments. It sacrifices some performance in pure WebSocket scenarios for increased compatibility and ease of use.

Choose WebSocket-Node for projects requiring high-performance WebSocket connections in modern environments, and SockJS-node for applications needing broader browser support and simplified implementation across different transport methods.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

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:

sockjs_url (string, required)
Transports which don't support cross-domain communication natively ('eventsource' to name one) use an iframe trick. A simple page is served from the SockJS server (using its foreign domain) and is placed in an invisible iframe. Code run from this iframe doesn't need to worry about cross-domain issues, as it's being run from domain local to the SockJS server. This iframe also does need to load SockJS javascript client library, and this option lets you specify its url (if you're unsure, point it to the latest minified SockJS client release, this is the default). You must explicitly specify this url on the server side for security reasons - we don't want the possibility of running any foreign javascript within the SockJS domain (aka cross site scripting attack). Also, sockjs javascript library is probably already cached by the browser - it makes sense to reuse the sockjs url you're using in normally.
prefix (string regex)
A url prefix for the server. All http requests which paths begins with selected prefix will be handled by SockJS. All other requests will be passed through, to previously registered handlers.
response_limit (integer)
Most streaming transports save responses on the client side and don't free memory used by delivered messages. Such transports need to be garbage-collected once in a while. `response_limit` sets a minimum number of bytes that can be send over a single http streaming request before it will be closed. After that client needs to open new request. Setting this value to one effectively disables streaming and will make streaming transports to behave like polling transports. The default value is 128K.
transports (Array of strings)
List of transports to enable. Select from `eventsource`, `htmlfile`, `jsonp-polling`, `websocket`, `websocket-raw`, `xhr-polling`, and `xhr-streaming`.
jsessionid (boolean or function)
Some hosting providers enable sticky sessions only to requests that have JSESSIONID cookie set. This setting controls if the server should set this cookie to a dummy value. By default setting JSESSIONID cookie is disabled. More sophisticated behaviour can be achieved by supplying a function.
log (function(severity, message))
It's quite useful, especially for debugging, to see some messages printed by a SockJS-node library. This is done using this `log` function, which is by default set to nothing. If this behaviour annoys you for some reason, override `log` setting with a custom handler. The following `severities` are used: `debug` (miscellaneous logs), `info` (requests logs), `error` (serious errors, consider filing an issue).
heartbeat_delay (milliseconds)
In order to keep proxies and load balancers from closing long running http requests we need to pretend that the connection is active and send a heartbeat packet once in a while. This setting controls how often this is done. By default a heartbeat packet is sent every 25 seconds.
disconnect_delay (milliseconds)
The server sends a `close` event when a client receiving connection have not been seen for a while. This delay is configured by this setting. By default the `close` event will be emitted when a receiving connection wasn't seen for 5 seconds.
disable_cors (boolean)
Enabling this option will prevent CORS headers from being included in the HTTP response. Can be used when the sockjs client is known to be connecting from the same origin as the sockjs server. This also disables the iframe HTML endpoint.

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:

Event: connection (connection)
A new connection has been successfully opened.

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:

Property: remoteAddress (string)
Last known IP address of the client.
Property: remotePort (number)
Last known port number of the client.
Property: address (object)
Hash with 'address' and 'port' fields.
Property: headers (object)
Hash containing various headers copied from last receiving request on that connection. Exposed headers include: `origin`, `referer` and `x-forwarded-for` (and friends). We explicitly do not grant access to `cookie` header, as using it may easily lead to security issues (for details read the section "Authorisation").
Property: url (string)
Url property copied from last request.
Property: pathname (string)
`pathname` from parsed url, for convenience.
Property: prefix (string)
Prefix of the url on which the request was handled.
Property: protocol (string)
Protocol used by the connection. Keep in mind that some protocols are indistinguishable - for example "xhr-polling" and "xdr-polling".
Property: readyState (integer)
Current state of the connection: 0-connecting, 1-open, 2-closing, 3-closed.
write(message)
Sends a message over opened connection. A message must be a non-empty string. It's illegal to send a message after the connection was closed (either after 'close' or 'end' method or 'close' event).
close([code], [reason])
Asks the remote client to disconnect. 'code' and 'reason' parameters are optional and can be used to share the reason of disconnection.
end()
Asks the remote client to disconnect with default 'code' and 'reason' values.

A Connection instance emits the following events:

Event: data (message)
A message arrived on the connection. Message is a unicode string.
Event: close ()
Connection was closed. This event is triggered exactly once for every connection.

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.

NPM DownloadsLast 30 Days