Coder Social home page Coder Social logo

sockjs-client's Introduction

SockJS-client

npm versionDependenciesChatContributor Covenant BrowserStack Status

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.

Summary

SockJS is a browser JavaScript library 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.

Under the hood SockJS tries to use native WebSockets first. If that fails it can use a variety of browser-specific transport protocols and presents them through WebSocket-like abstractions.

SockJS is intended to work for all modern browsers and in environments which don't support the WebSocket protocol -- for example, behind restrictive corporate proxies.

SockJS-client does require a server counterpart:

Philosophy:

  • The API should follow HTML5 Websockets API as closely as possible.
  • All the transports must support cross domain connections out of the box. It's possible and recommended to host a SockJS server on a different server than your main web site.
  • There is support for at least one streaming protocol for every major browser.
  • Streaming transports should work cross-domain and should support cookies (for cookie-based sticky sessions).
  • Polling transports are used as a fallback for old browsers and hosts behind restrictive proxies.
  • Connection establishment should be fast and lightweight.
  • No Flash inside (no need to open port 843 - which doesn't work through proxies, no need to host 'crossdomain.xml', no need to wait for 3 seconds in order to detect problems)

Subscribe to SockJS mailing list for discussions and support.

SockJS family

Work in progress:

Getting Started

SockJS mimics the WebSockets API, but instead of WebSocket there is a SockJS Javascript object.

First, you need to load the SockJS JavaScript library. For example, you can put that in your HTML head:

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>

After the script is loaded you can establish a connection with the SockJS server. Here's a simple example:

 var sock = new SockJS('https://mydomain.com/my_prefix');
 sock.onopen = function() {
     console.log('open');
     sock.send('test');
 };

 sock.onmessage = function(e) {
     console.log('message', e.data);
     sock.close();
 };

 sock.onclose = function() {
     console.log('close');
 };

SockJS-client API

SockJS class

Similar to the 'WebSocket' API, the 'SockJS' constructor takes one or more arguments:

var sockjs = new SockJS(url, _reserved, options);

url may contain a query string, if one is desired.

Where options is a hash which can contain:

  • server (string)

    String to append to url for actual data connection. Defaults to a random 4 digit number.

  • transports (string OR array of strings)

    Sometimes it is useful to disable some fallback transports. This option allows you to supply a list transports that may be used by SockJS. By default all available transports will be used.

  • sessionId (number OR function)

    Both client and server use session identifiers to distinguish connections. If you specify this option as a number, SockJS will use its random string generator function to generate session ids that are N-character long (where N corresponds to the number specified by sessionId). When you specify this option as a function, the function must return a randomly generated string. Every time SockJS needs to generate a session id it will call this function and use the returned string directly. If you don't specify this option, the default is to use the default random string generator to generate 8-character long session ids.

  • timeout (number)

    Specify a minimum timeout in milliseconds to use for the transport connections. By default this is dynamically calculated based on the measured RTT and the number of expected round trips. This setting will establish a minimum, but if the calculated timeout is higher, that will be used.

Although the 'SockJS' object tries to emulate the 'WebSocket' behaviour, it's impossible to support all of its features. An important SockJS limitation is the fact that you're not allowed to open more than one SockJS connection to a single domain at a time. This limitation is caused by an in-browser limit of outgoing connections - usually browsers don't allow opening more than two outgoing connections to a single domain. A single SockJS session requires those two connections - one for downloading data, the other for sending messages. Opening a second SockJS session at the same time would most likely block, and can result in both sessions timing out.

Opening more than one SockJS connection at a time is generally a bad practice. If you absolutely must do it, you can use multiple subdomains, using a different subdomain for every SockJS connection.

Supported transports, by browser (html served from http:// or https://)

Browser Websockets Streaming Polling
IE 6, 7 no no jsonp-polling
IE 8, 9 (cookies=no) no xdr-streaming † xdr-polling †
IE 8, 9 (cookies=yes) no iframe-htmlfile iframe-xhr-polling
IE 10 rfc6455 xhr-streaming xhr-polling
Chrome 6-13 hixie-76 xhr-streaming xhr-polling
Chrome 14+ hybi-10 / rfc6455 xhr-streaming xhr-polling
Firefox <10 no ‡ xhr-streaming xhr-polling
Firefox 10+ hybi-10 / rfc6455 xhr-streaming xhr-polling
Safari 5.x hixie-76 xhr-streaming xhr-polling
Safari 6+ rfc6455 xhr-streaming xhr-polling
Opera 10.70+ no ‡ iframe-eventsource iframe-xhr-polling
Opera 12.10+ rfc6455 xhr-streaming xhr-polling
Konqueror no no jsonp-polling
  • : IE 8+ supports [XDomainRequest]1, which is essentially a modified AJAX/XHR that can do requests across domains. But unfortunately it doesn't send any cookies, which makes it inappropriate for deployments when the load balancer uses JSESSIONID cookie to do sticky sessions.

  • : Firefox 4.0 and Opera 11.00 and shipped with disabled Websockets "hixie-76". They can still be enabled by manually changing a browser setting.

Supported transports, by browser (html served from file://)

Sometimes you may want to serve your html from "file://" address - for development or if you're using PhoneGap or similar technologies. But due to the Cross Origin Policy files served from "file://" have no Origin, and that means some of SockJS transports won't work. For this reason the SockJS transport table is different than usually, major differences are:

Browser Websockets Streaming Polling
IE 8, 9 same as above iframe-htmlfile iframe-xhr-polling
Other same as above iframe-eventsource iframe-xhr-polling

Supported transports, by name

Transport References
websocket (rfc6455) [rfc 6455]2
websocket (hixie-76) [draft-hixie-thewebsocketprotocol-76]3
websocket (hybi-10) [draft-ietf-hybi-thewebsocketprotocol-10]4
xhr-streaming Transport using [Cross domain XHR]5 [streaming]6 capability (readyState=3).
xdr-streaming Transport using [XDomainRequest]1 [streaming]6 capability (readyState=3).
eventsource [EventSource/Server-sent events]7.
iframe-eventsource [EventSource/Server-sent events]7 used from an [iframe via postMessage]8.
htmlfile [HtmlFile]9.
iframe-htmlfile [HtmlFile]9 used from an [iframe via postMessage]8.
xhr-polling Long-polling using [cross domain XHR]5.
xdr-polling Long-polling using [XDomainRequest]1.
iframe-xhr-polling Long-polling using normal AJAX from an [iframe via postMessage]8.
jsonp-polling Slow and old fashioned [JSONP polling]10. This transport will show "busy indicator" (aka: "spinning wheel") when sending data.

Connecting to SockJS without the client

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

Deployment

You should use a version of sockjs-client that supports the protocol used by your server. For example:

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>

For server-side deployment tricks, especially about load balancing and session stickiness, take a look at the SockJS-node readme.

Development and testing

SockJS-client needs node.js for running a test server and JavaScript minification. If you want to work on SockJS-client source code, checkout the git repo and follow these steps:

cd sockjs-client
npm install

To generate JavaScript, run:

gulp browserify

To generate minified JavaScript, run:

gulp browserify:min

Both commands output into the build directory.

Testing

Automated testing provided by:

Once you've compiled the SockJS-client you may want to check if your changes pass all the tests.

npm run test:browser_local

This will start karma and a test support server.

Browser Quirks

There are various browser quirks which we don't intend to address:

  • Pressing ESC in Firefox, before Firefox 20, closes the SockJS connection. For a workaround and discussion see #18.
  • jsonp-polling transport will show a "spinning wheel" (aka. "busy indicator") when sending data.
  • You can't open more than one SockJS connection to one domain at the same time due to the browser's limit of concurrent connections (this limit is not counting native WebSocket connections).
  • Although SockJS is trying to escape any strange Unicode characters (even invalid ones - like surrogates \xD800-\xDBFF or \xFFFE and \xFFFF) it's advisable to use only valid characters. Using invalid characters is a bit slower, and may not work with SockJS servers that have proper Unicode support.
  • Having a global function called onmessage or such is probably a bad idea, as it could be called by the built-in postMessage API.
  • From SockJS' point of view there is nothing special about SSL/HTTPS. Connecting between unencrypted and encrypted sites should work just fine.
  • Although SockJS does its best to support both prefix and cookie based sticky sessions, the latter may not work well cross-domain with browsers that don't accept third-party cookies by default (Safari). In order to get around this make sure you're connecting to SockJS from the same parent domain as the main site. For example 'sockjs.a.com' is able to set cookies if you're connecting from 'www.a.com' or 'a.com'.
  • Trying to connect from secure "https://" to insecure "http://" is not a good idea. The other way around should be fine.
  • Long polling is known to cause problems on Heroku, but a workaround for SockJS is available.
  • SockJS websocket transport is more stable over SSL. If you're a serious SockJS user then consider using SSL (more info).

Footnotes

  1. https://blogs.msdn.microsoft.com/ieinternals/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds/ 2 3

  2. https://www.rfc-editor.org/rfc/rfc6455.txt

  3. https://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76

  4. https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10

  5. https://secure.wikimedia.org/wikipedia/en/wiki/XMLHttpRequest#Cross-domain_requests 2

  6. http://www.debugtheweb.com/test/teststreaming.aspx 2

  7. https://html.spec.whatwg.org/multipage/comms.html#server-sent-events 2

  8. https://developer.mozilla.org/en/DOM/window.postMessage 2 3

  9. http://cometdaily.com/2007/11/18/ie-activexhtmlfile-transport-part-ii/ 2

  10. https://secure.wikimedia.org/wikipedia/en/wiki/JSONP

sockjs-client's People

Contributors

brycekahle avatar caoimhechaos avatar cgbystrom avatar davidben avatar dependabot[bot] avatar dvv avatar fafhrd91 avatar georgeosddev avatar glasser avatar harryadel avatar imkira avatar iyegoroff avatar jfarcand avatar jijojames18 avatar johnmaguire avatar kkirsche avatar konklone avatar lpinca avatar lukasdrgon avatar majek avatar manuelstofer avatar mquandalle avatar nehresma avatar ngocdaothanh avatar pl avatar rstoyanchev avatar squaremo avatar syberkitten avatar watsoncj avatar yannickcr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sockjs-client's Issues

`send` shouldn't allow complex data types

Only strings, as per websockets spec.
(we don't do Blobs and typed arrays for now)

It should behave in a similar way to what chrome does - converting a value to a string. For example if you try sending a number 1 a string 1 will be send.

XHR requests linger on behind haproxy

@shripadk on IRC reports

 [22:55] <shripadk> while behind a proxy (ex: haproxy)
 [22:55] <shripadk> i notice that if the backend server crashes
 [22:55] <shripadk> xhr requests linger on
 [22:55] <shripadk> looks like there is no timeout set client side
 [22:56] <shripadk> doesn't that cause unnecessary load on the server?

Htmlfile transport

In order to support JSESSIONID load balancing we need a streaming transport for IE that supports cookies. XDR is great, but it doesn't send cookies. Thus a need for something else - htmlfile for example.

Don't rely on Javascript PRNG

Javascript random numbers aren't cryptographically secure. Security research proved that in some cases they are easy to predict. We should consider using a custom PRNG:

http://baagoe.com/en/RandomMusings/javascript/

Or at least use the "entropy" from "info" request as a seed.

CDN 'sockjs-0.1.js' serves a 0.2 client.

Our application links to http://cdn.sockjs.org/sockjs-0.1.js, which we expected to always serve the latest 0.1-compatible client.

Before today, it served 0.1.2. But now, it serves 0.1.2.82.g295b. It appears this is code identical to 0.2, but with a different version number slapped on. This is breaking connection to our production 0.1 servers.

Any chance version 0.1.2.82.g295b can be revoked so that sockjs-0.1.js again serves 0.1.2?

sockjs disable back button for opera

I hit the back button once, nothing happens, hit it again I am taken back to where I came from. Sometimes required more hits.

in cleanup function there's hack for ie: iframe.src = "about:blank";
it's lead to the interception of back button for opera.

Solution (in utils.createIframe cleanup):

  • iframe.src = "about:blank";
  • if(!-[1,]) iframe.src = "about:blank"; // (!-[1,]) for detect ie, could be something else

Emit 'heartbeat' event.

This is not defined by the spec, but it appears that exposing underlying 'heartbeat' events could be useful.

Remember last working transport

After we've done transport discovery, and the connection gets broken, we shouldn't do the discovery again.

Instead, if user wants to reconnect, we should just reuse previously detected transport.

outdated tests

Please, update sockjs-client/tests server. It uses outdated SockJS.createServer() call
--Vladimir

`status` property on CloseEvent should be called `code`

I got that wrong. See sockjs-node bug. Spec clearly says:

Create an event that uses the CloseEvent interface, with the event name close, [...] whose wasClean attribute is initialized to true if the connection closed cleanly and false otherwise, whose code attribute is initialized to the WebSocket connection close code, and whose reason attribute is initialized to the WebSocket connection close reason decoded as UTF-8

trying to access a ws:// web socket server

Hi Majek & Co.

We've been hunting for a silver bullet. We have been developing an HTML 5 (Sencha Touch) application for 8 months. Use Web Socket to move JSON data to/from a SQL Server DB to the SQLite DB on devices. We have developed a server side listener based around the Alchemy websocket system. Which has served us well during the development phase and works well with our 'app' on iPhone/Pad .. having been wrapped by Phonegap etc.

We have been keeping a watch on possible solutions for Androids and have looked at a few. Over the past 24 hours we've made an attempt to get SockJS to work. It seems to us that it won't connect to our web socket server ... which has a ws:// address. ... like ws://222.333.555.111:50555

Are we wasting our time here? Does your client only talk to http:// addressed servers?

Would be interested to hear from you

Regards
Roger

AMD Compliance

Any chance this can be added? Should be as simple as

if typeof define is 'function'
   define SockJS
else
   window.SockJS = SockJS

Connection not closed on IE9 (using: iframe-htmlfile) when the browser is closed

  1. Connect to the (code below) server on IE9
  2. Either refresh the page (50% repo) or close the tab/browser (50% repo)

Observe no disconnect message by the server. Is this expected? A WebSocket connection (chrome) doesn't show the same behavior.

This is the server I was running to test (a quick modification of the echo.js server)

/*global require: false */
/*global __dirname: false */
/*global console: false */

var http = require('http');
var sockjs = require('sockjs');
var node_static = require('node-static');

// 1. Echo sockjs server
function do_nothing() {}

var sockjs_opts = {
    sockjs_url: "http://cdn.sockjs.org/sockjs-0.2.min.js",
    log: do_nothing
};

var sockjs_echo = sockjs.createServer(sockjs_opts);

var connections = {};
var nextConnectionId = 0;

function publishMessage(message)
{
    var c;
    for (c in connections)
    {
        if (connections.hasOwnProperty(c))
        {
            var connection = connections[c];
            connection.write(message);
        }
    }
}

function sockjs_connection(connection)
{
    connections[nextConnectionId] = connection;
    var connectionId = nextConnectionId;

    nextConnectionId += 1;

    var message = 'Connection from ' + connection.remoteAddress + ':' + connection.remotePort + ' with id ' + connectionId;
    console.log(message);
    publishMessage(message);

    function connection_data(message)
    {
        publishMessage(message);
    }

    function connection_close()
    {
        var message = 'Disconnect from ' + connection.remoteAddress + ':' + connection.remotePort + ' with id ' + connectionId;
        console.log(message);
        delete connections[connectionId];
        publishMessage(message);
    }

    connection.on('data', connection_data);
    connection.on('close', connection_close);
}

sockjs_echo.on('connection', sockjs_connection);

// 2. Static files server
var static_directory = new node_static.Server(__dirname);

// 3. Usual http stuff
var server = http.createServer();

function static_directory_listener(req, res)
{
    static_directory.serve(req, res);
}

function upgrade_listener(req, res)
{
    res.end();
}

server.addListener('request', static_directory_listener);
server.addListener('upgrade', upgrade_listener);

sockjs_echo.installHandlers(server, {prefix: '/echo'});

console.log(' [*] Listening on 0.0.0.0:9999');
server.listen(9999, '0.0.0.0');

"[object Object]"

Why you add object to empty string in send function ?
Object every time converts to "[object Object]".

that._transport.doSend(utils.quote('' + data));

Your test does not cover this situation, because each time they compare string and string, but not objects.
You need to replace "equal" and "equals" test function to "same".

robuster browser detection is needed

IE9 in standard document mode pretends to be a good browser. In particular, checking whether browser is IE with typeof _document.attachEvent === 'object' gives false negatives. This lead to subtle errors. To name one, jsonp-polling transport stops functioning correctly.

Proposed fix to jsonp-polling for IE is at #21

I believe we should determine browser once (then cache it in SockJS object) and more carefully

Framing overhaul: Don't JSON-encode everything

Currently, which I do admit is a bit stupid, everything passed to SockJS is json-encoded. That should not be necessary, especially for protocols that can do binaries - websockets.

This will require a major change in the protocol.

It's also not going to be simple due to the fact that we may need some encoding for the iframe communication.

Syntax error under IE7

I systematically get a syntax error at line 1 under IE7 if I try to connect with sockjs client. To reproduce the issue, just try to create a new SockJS object like this:

<html>
<body>
  <script src="http://cdn.sockjs.org/sockjs-0.1.js"></script>
  <script>new SockJS('http://example.com/');</script>
</body>
</html>

In Sockjs 0.2 safari less likely to use native websockets

It looks that since 0.2 Safari is less likely to use websockets and more often falls back to xhr-polling.

This may be caused by general slowness of safari, or safari websockets implementation.

For example, connecting to host in the same network takes about 14ms in safari and 4ms in chrome.

iframe-htmlfile not stable in ie8

During the work on #52 we realized that iframe-htmlfile is not as stable as it should be. It seems to work okay in generic case, but it often fails to establish connection again after hitting F5/refresh.

To reproduce:

Inline license

The license should be included verbatim at the top of the released file.

Does "protocols" not work at all?

var sockjs = new SockJS(url, protocols, options); <-- it looks like you can pass ['websockets'] to protocols, but that doesn't seem to be working.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.