{"id":13403069,"url":"https://github.com/sockjs/sockjs-node","last_synced_at":"2025-05-13T18:04:54.685Z","repository":{"id":524362,"uuid":"2088982","full_name":"sockjs/sockjs-node","owner":"sockjs","description":"WebSocket emulation - Node.js server","archived":false,"fork":false,"pushed_at":"2024-12-24T10:08:22.000Z","size":547,"stargazers_count":2102,"open_issues_count":19,"forks_count":307,"subscribers_count":60,"default_branch":"main","last_synced_at":"2025-04-30T12:21:41.104Z","etag":null,"topics":["javascript","node","nodejs","real-time","sockjs","websocket"],"latest_commit_sha":null,"homepage":"http://sockjs.org","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sockjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null},"funding":{"tidelift":"npm/sockjs-client"}},"created_at":"2011-07-22T14:22:50.000Z","updated_at":"2025-04-28T06:08:25.000Z","dependencies_parsed_at":"2023-07-05T15:02:54.393Z","dependency_job_id":"17014d21-7580-4341-8b4e-6695315446cd","html_url":"https://github.com/sockjs/sockjs-node","commit_stats":{"total_commits":486,"total_committers":46,"mean_commits":"10.565217391304348","dds":"0.37860082304526754","last_synced_commit":"23a3d1f1f49598bd568af96f25e843aa876161d7"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockjs%2Fsockjs-node","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockjs%2Fsockjs-node/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockjs%2Fsockjs-node/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sockjs%2Fsockjs-node/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sockjs","download_url":"https://codeload.github.com/sockjs/sockjs-node/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252448556,"owners_count":21749492,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","node","nodejs","real-time","sockjs","websocket"],"created_at":"2024-07-30T19:01:25.003Z","updated_at":"2025-05-05T23:08:33.982Z","avatar_url":"https://github.com/sockjs.png","language":"JavaScript","readme":"# SockJS-node\n\n[![npm version](https://img.shields.io/npm/v/sockjs.svg?style=flat-square)](https://www.npmjs.com/package/sockjs)[![Dependencies](https://img.shields.io/david/sockjs/sockjs-node.svg?style=flat-square)](https://david-dm.org/sockjs/sockjs-node)\n\n# SockJS for enterprise\n\nAvailable as part of the Tidelift Subscription.\n\nThe 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?utm_source=npm-sockjs\u0026utm_medium=referral\u0026utm_campaign=enterprise\u0026utm_term=repo)\n\n# SockJS family\n\n  * [SockJS-client](https://github.com/sockjs/sockjs-client) JavaScript client library\n  * [SockJS-node](https://github.com/sockjs/sockjs-node) Node.js server\n  * [SockJS-erlang](https://github.com/sockjs/sockjs-erlang) Erlang server\n  * [SockJS-tornado](https://github.com/MrJoes/sockjs-tornado) Python/Tornado server\n  * [vert.x](https://github.com/eclipse/vert.x) Java/vert.x server\n\nWork in progress:\n\n  * [SockJS-ruby](https://github.com/nyarly/sockjs-ruby)\n  * [SockJS-netty](https://github.com/cgbystrom/sockjs-netty)\n  * [SockJS-gevent](https://github.com/sdiehl/sockjs-gevent) ([and a fork](https://github.com/njoyce/sockjs-gevent))\n  * [pyramid-SockJS](https://github.com/fafhrd91/pyramid_sockjs)\n  * [wildcloud-websockets](https://github.com/wildcloud/wildcloud-websockets)\n  * [SockJS-cyclone](https://github.com/flaviogrossi/sockjs-cyclone)\n  * [SockJS-twisted](https://github.com/Fugiman/sockjs-twisted/)\n  * [wai-SockJS](https://github.com/Palmik/wai-sockjs)\n  * [SockJS-perl](https://github.com/vti/sockjs-perl)\n  * [SockJS-go](https://github.com/igm/sockjs-go/)\n  * [actix/sockjs](https://github.com/actix/sockjs) for Rust\n\n⚠️️ **ATTENTION** This is pre-release documentation. The documentation for the \nlatest stable release is at: https://github.com/sockjs/sockjs-node/tree/v0.3.19 ️⚠️\n\n# What is SockJS?\n\nSockJS is a JavaScript library (for browsers) that provides a WebSocket-like\nobject. SockJS gives you a coherent, cross-browser, Javascript API\nwhich creates a low latency, full duplex, cross-domain communication\nchannel between the browser and the web server, with WebSockets or without.\nThis necessitates the use of a server, which this is one version of, for Node.js.\n\n\n# SockJS-node server\n\nSockJS-node is a Node.js server side counterpart of\n[SockJS-client browser library](https://github.com/sockjs/sockjs-client).\n\nTo install `sockjs-node` run:\n\n    npm install sockjs\n\nA simplified echo SockJS server could look more or less like:\n\n```javascript\nconst http = require('http');\nconst sockjs = require('sockjs');\n\nconst echo = sockjs.createServer({ prefix:'/echo' });\necho.on('connection', function(conn) {\n  conn.on('data', function(message) {\n    conn.write(message);\n  });\n  conn.on('close', function() {});\n});\n\nconst server = http.createServer();\necho.attach(server);\nserver.listen(9999, '0.0.0.0');\n```\n\n(Take look at\n[examples](https://github.com/sockjs/sockjs-node/tree/main/examples/echo)\ndirectory for a complete version.)\n\nSubscribe to\n[SockJS mailing list](https://groups.google.com/forum/#!forum/sockjs) for\ndiscussions and support.\n\n\n# SockJS-node API\n\nThe API design is based on common Node APIs like the\n[Streams API](https://nodejs.org/api/stream.html) or the\n[Http.Server API](https://nodejs.org/api/http.html#http_class_http_server).\n\n## Server class\n\nSockJS module is generating a `Server` class, similar to\n[Node.js http.createServer](https://nodejs.org/api/http.html#http_http_createserver_requestlistener)\nmodule.\n\n```javascript\nconst sockjs_server = sockjs.createServer(options);\n```\n\nWhere `options` is a hash which can contain:\n\n\u003cdl\u003e\n\u003cdt\u003esockjs_url (string, required)\u003c/dt\u003e\n\u003cdd\u003eTransports which don't support cross-domain communication natively\n   ('eventsource' to name one) use an iframe trick. A simple page is\n   served from the SockJS server (using its foreign domain) and is\n   placed in an invisible iframe. Code run from this iframe doesn't\n   need to worry about cross-domain issues, as it's being run from\n   domain local to the SockJS server. This iframe also does need to\n   load SockJS javascript client library, and this option lets you specify\n   its url (if you're unsure, point it to\n   \u003ca href=\"https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js\"\u003e\n   the latest minified SockJS client release\u003c/a\u003e, this is the default).\n   You must explicitly specify this url on the server side for security\n   reasons - we don't want the possibility of running any foreign\n   javascript within the SockJS domain (aka cross site scripting attack).\n   Also, sockjs javascript library is probably already cached by the\n   browser - it makes sense to reuse the sockjs url you're using in\n   normally.\u003c/dd\u003e\n\n\u003cdt\u003eprefix (string regex)\u003c/dt\u003e\n\u003cdd\u003eA url prefix for the server. All http requests which paths begins\n   with selected prefix will be handled by SockJS. All other requests\n   will be passed through, to previously registered handlers.\u003c/dd\u003e\n\n\u003cdt\u003eresponse_limit (integer)\u003c/dt\u003e\n\u003cdd\u003eMost streaming transports save responses on the client side and\n   don't free memory used by delivered messages. Such transports need\n   to be garbage-collected once in a while. `response_limit` sets\n   a minimum number of bytes that can be send over a single http streaming\n   request before it will be closed. After that client needs to open\n   new request. Setting this value to one effectively disables\n   streaming and will make streaming transports to behave like polling\n   transports. The default value is 128K.\u003c/dd\u003e\n\n\u003cdt\u003etransports (Array of strings)\u003c/dt\u003e\n\u003cdd\u003eList of transports to enable. Select from `eventsource`, `htmlfile`,\n`jsonp-polling`, `websocket`, `websocket-raw`, `xhr-polling`, \nand `xhr-streaming`.\u003c/dd\u003e\n\n\u003cdt\u003ejsessionid (boolean or function)\u003c/dt\u003e\n\u003cdd\u003eSome hosting providers enable sticky sessions only to requests that\n  have JSESSIONID cookie set. This setting controls if the server should\n  set this cookie to a dummy value. By default setting JSESSIONID cookie\n  is disabled. More sophisticated behaviour can be achieved by supplying\n  a function.\u003c/dd\u003e\n\n\u003cdt\u003elog (function(severity, message))\u003c/dt\u003e\n\u003cdd\u003eIt's quite useful, especially for debugging, to see some messages\n  printed by a SockJS-node library. This is done using this `log`\n  function, which is by default set to nothing. If this\n  behaviour annoys you for some reason, override `log` setting with a\n  custom handler.  The following `severities` are used: `debug`\n  (miscellaneous logs), `info` (requests logs), `error` (serious\n  errors, consider filing an issue).\u003c/dd\u003e\n\n\u003cdt\u003eheartbeat_delay (milliseconds)\u003c/dt\u003e\n\u003cdd\u003eIn order to keep proxies and load balancers from closing long\n  running http requests we need to pretend that the connection is\n  active and send a heartbeat packet once in a while. This setting\n  controls how often this is done. By default a heartbeat packet is\n  sent every 25 seconds.  \u003c/dd\u003e\n\n\u003cdt\u003edisconnect_delay (milliseconds)\u003c/dt\u003e\n\u003cdd\u003eThe server sends a `close` event when a client receiving\n  connection have not been seen for a while. This delay is configured\n  by this setting. By default the `close` event will be emitted when a\n  receiving connection wasn't seen for 5 seconds.  \u003c/dd\u003e\n\n\u003cdt\u003edisable_cors (boolean)\u003c/dt\u003e\n\u003cdd\u003eEnabling this option will prevent\n  \u003ca href=\"https://en.wikipedia.org/wiki/Cross-origin_resource_sharing\"\u003eCORS\u003c/a\u003e\n  headers from being included in the HTTP response. Can be used when the\n  sockjs client is known to be connecting from the same origin as the \n  sockjs server. This also disables the iframe HTML endpoint.\u003c/dd\u003e\n\u003c/dl\u003e\n\n\n## Server instance\n\nOnce you have create `Server` instance you can hook it to the\n[http.Server instance](https://nodejs.org/api/http.html#http_class_http_server).\n\n```javascript\nvar http_server = http.createServer();\nsockjs_server.attach(http_server);\nhttp_server.listen(...);\n```\n\n`Server` instance is an\n[EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter),\nand emits following event:\n\n\u003cdl\u003e\n\u003cdt\u003eEvent: connection (connection)\u003c/dt\u003e\n\u003cdd\u003eA new connection has been successfully opened.\u003c/dd\u003e\n\u003c/dl\u003e\n\nAll http requests that don't go under the path selected by `prefix`\nwill remain unanswered and will be passed to previously registered\nhandlers. You must install your custom http handlers before calling\n`attach`. You can remove the SockJS handler later with `detach`.\n\n## Connection instance\n\nA `Connection` instance supports\n[Node Stream API](https://nodejs.org/api/stream.html) and\nhas following methods and properties:\n\n\u003cdl\u003e\n\u003cdt\u003eProperty: remoteAddress (string)\u003c/dt\u003e\n\u003cdd\u003eLast known IP address of the client.\u003c/dd\u003e\n\n\u003cdt\u003eProperty: remotePort (number)\u003c/dt\u003e\n\u003cdd\u003eLast known port number of the client.\u003c/dd\u003e\n\n\u003cdt\u003eProperty: address (object)\u003c/dt\u003e\n\u003cdd\u003eHash with 'address' and 'port' fields.\u003c/dd\u003e\n\n\u003cdt\u003eProperty: headers (object)\u003c/dt\u003e\n\u003cdd\u003eHash containing various headers copied from last receiving request\n    on that connection. Exposed headers include: `origin`, `referer`\n    and `x-forwarded-for` (and friends). We explicitly do not grant\n    access to `cookie` header, as using it may easily lead to security\n    issues (for details read the section \"Authorisation\").\u003c/dd\u003e\n\n\u003cdt\u003eProperty: url (string)\u003c/dt\u003e\n\u003cdd\u003e\u003ca href=\"https://nodejs.org/api/http.html#http_message_url\"\u003eUrl\u003c/a\u003e\n    property copied from last request.\u003c/dd\u003e\n\n\u003cdt\u003eProperty: pathname (string)\u003c/dt\u003e\n\u003cdd\u003e`pathname` from parsed url, for convenience.\u003c/dd\u003e\n\n\u003cdt\u003eProperty: prefix (string)\u003c/dt\u003e\n\u003cdd\u003ePrefix of the url on which the request was handled.\u003c/dd\u003e\n\n\u003cdt\u003eProperty: protocol (string)\u003c/dt\u003e\n\u003cdd\u003eProtocol used by the connection. Keep in mind that some protocols\n   are indistinguishable - for example \"xhr-polling\" and \"xdr-polling\".\u003c/dd\u003e\n\n\u003cdt\u003eProperty: readyState (integer)\u003c/dt\u003e\n\u003cdd\u003eCurrent state of the connection:\n   0-connecting, 1-open, 2-closing, 3-closed.\u003c/dd\u003e\n\n\u003cdt\u003ewrite(message)\u003c/dt\u003e\n\u003cdd\u003eSends a message over opened connection. A message must be a\n  non-empty string. It's illegal to send a message after the connection was\n  closed (either after 'close' or 'end' method or 'close' event).\u003c/dd\u003e\n\n\u003cdt\u003eclose([code], [reason])\u003c/dt\u003e\n\u003cdd\u003eAsks the remote client to disconnect. 'code' and 'reason'\n   parameters are optional and can be used to share the reason of\n   disconnection.\u003c/dd\u003e\n\n\u003cdt\u003eend()\u003c/dt\u003e\n\u003cdd\u003eAsks the remote client to disconnect with default 'code' and\n   'reason' values.\u003c/dd\u003e\n\n\u003c/dl\u003e\n\nA `Connection` instance emits the following events:\n\n\u003cdl\u003e\n\u003cdt\u003eEvent: data (message)\u003c/dt\u003e\n\u003cdd\u003eA message arrived on the connection. Message is a unicode\n  string.\u003c/dd\u003e\n\n\u003cdt\u003eEvent: close ()\u003c/dt\u003e\n\u003cdd\u003eConnection was closed. This event is triggered exactly once for\n   every connection.\u003c/dd\u003e\n\u003c/dl\u003e\n\nFor example:\n\n```javascript\nsockjs_server.on('connection', function(conn) {\n  console.log('connection' + conn);\n  conn.on('close', function() {\n    console.log('close ' + conn);\n  });\n  conn.on('data', function(message) {\n    console.log('message ' + conn, message);\n  });\n});\n```\n\n## Footnote\n\nA fully working echo server does need a bit more boilerplate (to\nhandle requests unanswered by SockJS), see the\n[`echo` example](https://github.com/sockjs/sockjs-node/tree/main/examples/echo)\nfor a complete code.\n\n# Examples\n\nIf you want to see samples of running code, take a look at:\n\n * [./examples/echo](https://github.com/sockjs/sockjs-node/tree/main/examples/echo)\n   directory, which contains a full example of a echo server.\n * [./tests/test_server](https://github.com/sockjs/sockjs-node/tree/main/tests/test_server) a standard SockJS test server.\n\n\n# Connecting to SockJS-node without the client\n\nAlthough the main point of SockJS it to enable browser-to-server\nconnectivity, it is possible to connect to SockJS from an external\napplication. Any SockJS server complying with 0.3 protocol does\nsupport a raw WebSocket url. The raw WebSocket url for the test server\nlooks like:\n\n * ws://localhost:8081/echo/websocket\n\nYou can connect any WebSocket RFC 6455 compliant WebSocket client to\nthis url. This can be a command line client, external application,\nthird party code or even a browser (though I don't know why you would\nwant to do so).\n\nNote: This endpoint will *not send any heartbeat packets*.\n\n\n# Deployment and load balancing\n\nThere are two issues that need to be considered when planning a\nnon-trivial SockJS-node deployment: WebSocket-compatible load balancer\nand sticky sessions (aka session affinity).\n\n## WebSocket compatible load balancer\n\nOften WebSockets don't play nicely with proxies and load balancers.\nDeploying a SockJS server behind Nginx or Apache could be painful.\n\nFortunately recent versions of an excellent load balancer\n[HAProxy](http://haproxy.1wt.eu/) are able to proxy WebSocket\nconnections. We propose to put HAProxy as a front line load balancer\nand use it to split SockJS traffic from normal HTTP data. Take a look\nat the sample\n[SockJS HAProxy configuration](https://github.com/sockjs/sockjs-node/blob/main/examples/haproxy.cfg).\n\nThe config also shows how to use HAproxy balancing to split traffic\nbetween multiple Node.js servers. You can also do balancing using dns\nnames.\n\n## Sticky sessions\n\nIf you plan deploying more than one SockJS server, you must make sure\nthat all HTTP requests for a single session will hit the same server.\nSockJS has two mechanisms that can be useful to achieve that:\n\n * Urls are prefixed with server and session id numbers, like:\n   `/resource/\u003cserver_number\u003e/\u003csession_id\u003e/transport`.  This is\n   useful for load balancers that support prefix-based affinity\n   (HAProxy does).\n * `JSESSIONID` cookie is being set by SockJS-node. Many load\n   balancers turn on sticky sessions if that cookie is set. This\n   technique is derived from Java applications, where sticky sessions\n   are often necessary. HAProxy does support this method, as well as\n   some hosting providers, for example CloudFoundry.  In order to\n   enable this method on the client side, please supply a\n   `cookie:true` option to SockJS constructor.\n\n\n# Development and testing\n\nIf you want to work on SockJS-node source code, you need to clone the\ngit repo and follow these steps. First you need to install\ndependencies:\n\n    cd sockjs-node\n    npm install\n\nIf compilation succeeds you may want to test if your changes pass all\nthe tests. Currently, there are two separate test suites.\n\n## SockJS-protocol Python tests\n\nTo run it run something like:\n\n    ./scripts/test.sh\n\nFor details see\n[SockJS-protocol README](https://github.com/sockjs/sockjs-protocol#readme).\n\n## SockJS-client Karma tests\n\nTo run it run something like:\n\n    cd sockjs-client\n    npm run test:browser_local\n\nFor details see\n[SockJS-client README](https://github.com/sockjs/sockjs-client#readme).\n\n# Various issues and design considerations\n\n## Authorisation\n\nSockJS-node does not expose cookies to the application. This is done\ndeliberately as using cookie-based authorisation with SockJS simply\ndoesn't make sense and will lead to security issues.\n\nCookies are a contract between a browser and an http server, and are\nidentified by a domain name. If a browser has a cookie set for\nparticular domain, it will pass it as a part of all http requests to\nthe host. But to get various transports working, SockJS uses a middleman\n- an iframe hosted from target SockJS domain. That means the server\nwill receive requests from the iframe, and not from the real\ndomain. The domain of an iframe is the same as the SockJS domain. The\nproblem is that any website can embed the iframe and communicate with\nit - and request establishing SockJS connection. Using cookies for\nauthorisation in this scenario will result in granting full access to\nSockJS communication with your website from any website. This is a\nclassic CSRF attack.\n\nBasically - cookies are not suited for SockJS model. If you want to\nauthorise a session - provide a unique token on a page, send it as a\nfirst thing over SockJS connection and validate it on the server\nside. In essence, this is how cookies work.\n\n\n## Deploying SockJS on Heroku\n\nLong polling is known to cause problems on Heroku, but\n[workaround for SockJS is available](https://github.com/sockjs/sockjs-node/issues/57#issuecomment-5242187).\n","funding_links":["https://tidelift.com/funding/github/npm/sockjs-client","https://tidelift.com/subscription/pkg/npm-sockjs?utm_source=npm-sockjs\u0026utm_medium=referral\u0026utm_campaign=enterprise\u0026utm_term=repo"],"categories":["JavaScript","CoffeeScript","Repository","Packages","WebSockets","Tools per Language","包"],"sub_categories":["Real-time","Node.js"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsockjs%2Fsockjs-node","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsockjs%2Fsockjs-node","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsockjs%2Fsockjs-node/lists"}