SockJS-client is a browser JavaScript library that provides a WebSocket-like object for establishing cross-browser, full-duplex communication channels between browsers and web servers.
—
SockJS-client uses an intelligent transport fallback system that automatically selects the best available communication method based on browser capabilities, network environment, and user configuration. It supports 11+ different transport protocols ranging from native WebSockets to JSONP polling.
The transport system attempts to use the most efficient protocol available, falling back to alternatives when necessary.
/**
* Available transport types in priority order
*/
const availableTransports = [
'websocket', // Native WebSocket (fastest)
'xhr-streaming', // XHR with streaming
'xdr-streaming', // XDomainRequest streaming (IE8-9)
'eventsource', // Server-Sent Events
'iframe-eventsource', // EventSource via iframe
'htmlfile', // HtmlFile transport (IE)
'iframe-htmlfile', // HtmlFile via iframe
'xhr-polling', // XHR long-polling
'xdr-polling', // XDomainRequest polling (IE8-9)
'iframe-xhr-polling', // XHR polling via iframe
'jsonp-polling' // JSONP polling (slowest, widest compatibility)
];
/**
* Constructor options for transport configuration
*/
interface SockJSOptions {
/** Transport whitelist - restrict allowed transports */
transports?: string | string[];
/** Transport-specific configuration options */
transportOptions?: {
[transportName: string]: any;
};
/** Minimum timeout for transport connections (ms) */
timeout?: number;
}Basic Transport Configuration:
// Allow all transports (default behavior)
const sock1 = new SockJS('https://example.com/sockjs');
// Restrict to WebSocket and XHR only
const sock2 = new SockJS('https://example.com/sockjs', null, {
transports: ['websocket', 'xhr-streaming', 'xhr-polling']
});
// Allow only polling transports (for restrictive firewalls)
const sock3 = new SockJS('https://example.com/sockjs', null, {
transports: ['xhr-polling', 'jsonp-polling']
});
// Force specific transport for testing
const sock4 = new SockJS('https://example.com/sockjs', null, {
transports: 'websocket' // String or array
});Individual transport protocols can be configured with specific parameters.
/**
* Transport-specific configuration options
*/
interface TransportOptions {
/** WebSocket transport options */
'websocket'?: {
heartbeat?: number; // Heartbeat interval (ms)
timeout?: number; // Connection timeout (ms)
};
/** XHR-based transport options */
'xhr-streaming'?: {
timeout?: number; // Request timeout (ms)
withCredentials?: boolean; // Include credentials
};
'xhr-polling'?: {
timeout?: number; // Request timeout (ms)
withCredentials?: boolean; // Include credentials
};
/** EventSource transport options */
'eventsource'?: {
timeout?: number; // Connection timeout (ms)
};
/** JSONP transport options */
'jsonp-polling'?: {
timeout?: number; // Request timeout (ms)
callbackName?: string; // Custom callback name
};
}Transport Options Usage:
const sock = new SockJS('https://example.com/sockjs', null, {
transports: ['websocket', 'xhr-streaming', 'xhr-polling'],
transportOptions: {
'websocket': {
heartbeat: 30000, // 30 second heartbeat
timeout: 10000 // 10 second connection timeout
},
'xhr-streaming': {
timeout: 15000, // 15 second request timeout
withCredentials: true // Include cookies
},
'xhr-polling': {
timeout: 5000, // 5 second polling timeout
withCredentials: true
}
}
});Configure connection and transport timeouts for different network conditions.
/**
* Timeout configuration options
*/
interface TimeoutOptions {
/**
* Minimum timeout for transport connections (milliseconds)
* Default: Calculated dynamically based on RTT
* Range: Typically 300ms to several seconds
*/
timeout?: number;
}
/**
* Internal timeout calculation (for reference)
* - If RTT > 100ms: timeout = 4 * RTT (minimum 400ms)
* - If RTT <= 100ms: timeout = 300ms + RTT
* - User-specified timeout establishes minimum value
*/Timeout Configuration Examples:
// Use default timeout calculation
const sock1 = new SockJS('https://example.com/sockjs');
// Set minimum timeout of 10 seconds
const sock2 = new SockJS('https://example.com/sockjs', null, {
timeout: 10000
});
// Very aggressive timeout for fast networks
const sock3 = new SockJS('https://example.com/sockjs', null, {
timeout: 1000,
transports: ['websocket', 'xhr-streaming']
});
// Conservative timeout for slow/unreliable networks
const sock4 = new SockJS('https://example.com/sockjs', null, {
timeout: 30000,
transports: ['xhr-polling', 'jsonp-polling']
});Detailed information about each transport type and when they are used.
High-performance transports that maintain persistent connections for real-time communication.
/**
* Streaming transport characteristics
*/
const streamingTransports = {
'websocket': {
description: 'Native WebSocket protocol (RFC 6455)',
pros: ['Lowest latency', 'Bidirectional', 'Full-duplex', 'Standard protocol'],
cons: ['Blocked by some proxies', 'Not supported in old browsers'],
browserSupport: 'IE 10+, Chrome 14+, Firefox 10+, Safari 6+',
fallback: 'xhr-streaming'
},
'xhr-streaming': {
description: 'XMLHttpRequest with streaming response',
pros: ['Good performance', 'Wide browser support', 'Works through most proxies'],
cons: ['HTTP overhead', 'Unidirectional', 'Browser connection limits'],
browserSupport: 'IE 10+, All modern browsers',
fallback: 'xhr-polling'
},
'xdr-streaming': {
description: 'XDomainRequest streaming (IE 8-9 only)',
pros: ['Cross-domain support in IE 8-9', 'Streaming capability'],
cons: ['IE-specific', 'No cookies', 'Limited headers'],
browserSupport: 'IE 8-9 only',
fallback: 'iframe-htmlfile'
},
'eventsource': {
description: 'Server-Sent Events (HTML5)',
pros: ['Built-in reconnection', 'Standard protocol', 'Event-based'],
cons: ['Unidirectional only', 'Browser connection limits'],
browserSupport: 'IE 10+, All modern browsers (not IE 8-9)',
fallback: 'xhr-streaming'
}
};Fallback transports that simulate real-time communication through periodic requests.
/**
* Polling transport characteristics
*/
const pollingTransports = {
'xhr-polling': {
description: 'XMLHttpRequest long-polling',
pros: ['Reliable', 'Works through proxies', 'Good browser support'],
cons: ['Higher latency', 'More server resources', 'HTTP overhead'],
browserSupport: 'IE 10+, All modern browsers',
fallback: 'jsonp-polling'
},
'xdr-polling': {
description: 'XDomainRequest polling (IE 8-9)',
pros: ['Cross-domain in IE 8-9', 'Reliable'],
cons: ['IE-specific', 'No cookies', 'Higher latency'],
browserSupport: 'IE 8-9 only',
fallback: 'iframe-xhr-polling'
},
'jsonp-polling': {
description: 'JSONP polling for maximum compatibility',
pros: ['Universal browser support', 'Works around CORS issues'],
cons: ['Highest latency', 'Most overhead', 'Shows loading indicator'],
browserSupport: 'All browsers including IE 6-7',
fallback: 'Connection failure'
}
};Specialized transports that use iframes to work around browser limitations.
/**
* Iframe transport characteristics
*/
const iframeTransports = {
'iframe-eventsource': {
description: 'EventSource running in iframe with postMessage',
pros: ['Cross-domain capability', 'Streaming', 'Cookie support'],
cons: ['Complex setup', 'iframe overhead', 'Limited to specific scenarios'],
browserSupport: 'Browsers supporting postMessage and EventSource',
fallback: 'iframe-xhr-polling'
},
'iframe-htmlfile': {
description: 'HtmlFile transport via iframe (IE specific)',
pros: ['Persistent connection in IE', 'Cookie support'],
cons: ['IE-specific', 'Complex implementation', 'iframe overhead'],
browserSupport: 'IE 8-9 primarily',
fallback: 'iframe-xhr-polling'
},
'iframe-xhr-polling': {
description: 'XHR polling in iframe with postMessage',
pros: ['Cross-domain support', 'Cookie support', 'Wide compatibility'],
cons: ['Higher overhead', 'iframe complexity', 'Polling latency'],
browserSupport: 'Browsers supporting postMessage',
fallback: 'jsonp-polling'
}
};Understanding which transports are selected based on browser capabilities and environment.
/**
* Transport selection by browser (modern versions)
*/
const desktopBrowserTransports = {
'Chrome 14+': ['websocket', 'xhr-streaming', 'xhr-polling'],
'Firefox 10+': ['websocket', 'xhr-streaming', 'xhr-polling'],
'Safari 6+': ['websocket', 'xhr-streaming', 'xhr-polling'],
'Edge': ['websocket', 'xhr-streaming', 'xhr-polling'],
'IE 11': ['websocket', 'xhr-streaming', 'xhr-polling'],
'IE 10': ['websocket', 'xhr-streaming', 'xhr-polling'],
'IE 8-9 (same domain)': ['xdr-streaming', 'xdr-polling'],
'IE 8-9 (cross domain)': ['iframe-htmlfile', 'iframe-xhr-polling'],
'IE 6-7': ['jsonp-polling']
};/**
* Transport selection for mobile browsers
*/
const mobileBrowserTransports = {
'iOS Safari': ['websocket', 'xhr-streaming', 'xhr-polling'],
'Android Chrome': ['websocket', 'xhr-streaming', 'xhr-polling'],
'Android Browser (old)': ['xhr-streaming', 'xhr-polling', 'jsonp-polling'],
'Opera Mobile': ['xhr-streaming', 'xhr-polling'],
'Windows Phone': ['websocket', 'xhr-streaming', 'xhr-polling']
};Configure transports based on deployment environment and network conditions.
Corporate Network (Restrictive Proxy):
// Conservative configuration for corporate environments
const corporateSock = new SockJS('https://example.com/sockjs', null, {
transports: ['xhr-polling', 'jsonp-polling'], // Avoid WebSocket/streaming
timeout: 15000, // Longer timeout for slow networks
transportOptions: {
'xhr-polling': {
timeout: 10000,
withCredentials: true // Maintain session
}
}
});High-Performance Network:
// Optimized for fast, reliable networks
const fastSock = new SockJS('https://example.com/sockjs', null, {
transports: ['websocket', 'xhr-streaming'], // Only fastest transports
timeout: 3000, // Aggressive timeout
transportOptions: {
'websocket': {
heartbeat: 15000 // Frequent heartbeat
}
}
});Mobile/Unreliable Network:
// Configuration for mobile or unreliable networks
const mobileSock = new SockJS('https://example.com/sockjs', null, {
transports: ['websocket', 'xhr-streaming', 'xhr-polling'],
timeout: 20000, // Patient timeout
transportOptions: {
'websocket': {
heartbeat: 45000 // Less frequent heartbeat
},
'xhr-polling': {
timeout: 8000
}
}
});Development/Testing:
// Force specific transport for testing
const testSock = new SockJS('https://example.com/sockjs', null, {
transports: 'jsonp-polling', // Test worst-case scenario
timeout: 30000
});
// Test transport fallback
const fallbackTestSock = new SockJS('https://example.com/sockjs', null, {
transports: ['fake-transport', 'xhr-polling'], // Will skip fake and use xhr
timeout: 5000
});Sophisticated transport configuration for specialized use cases.
/**
* Configure session handling for load-balanced environments
*/
const sessionSock = new SockJS('https://example.com/sockjs', null, {
server: 'server-01', // Pin to specific server
sessionId: () => 'session-' + Date.now(), // Custom session ID
transports: ['websocket', 'xhr-streaming', 'xhr-polling'],
transportOptions: {
'xhr-streaming': {
withCredentials: true // Include cookies for sticky sessions
},
'xhr-polling': {
withCredentials: true
}
}
});/**
* Configure for cross-domain connections
*/
const crossDomainSock = new SockJS('https://api.example.com/sockjs', null, {
// Use transports that support cross-domain
transports: [
'websocket', // Native cross-domain support
'iframe-eventsource', // Cross-domain via iframe
'iframe-xhr-polling',
'jsonp-polling' // Always cross-domain capable
],
transportOptions: {
'jsonp-polling': {
timeout: 8000
}
}
});/**
* Monitor transport performance and selection
*/
const monitoredSock = new SockJS('https://example.com/sockjs', null, {
transports: ['websocket', 'xhr-streaming', 'xhr-polling']
});
monitoredSock.onopen = function() {
console.log('Connected using transport:', this.transport);
console.log('Connection URL:', this.url);
// Log transport performance
const startTime = Date.now();
this.send('ping');
this.onmessage = function(event) {
if (event.data === 'pong') {
console.log('Round-trip time:', Date.now() - startTime, 'ms');
}
};
};
// Monitor transport failures
monitoredSock.addEventListener('error', function() {
console.log('Transport error, will try fallback');
});Important limitations and considerations when configuring transports.
/**
* Browser connection limitations
*/
const connectionLimits = {
maxConnectionsPerDomain: 6, // Most browsers
maxConnectionsPerDomainIE8: 2, // IE 8 specifically
sockjsConnectionsRequired: 2, // One for sending, one for receiving
// Implications
maxSockJSConnectionsPerDomain: 1, // Generally only one SockJS per domain
workaround: 'Use subdomains for multiple connections'
};Multiple Connection Workaround:
// DON'T: Multiple connections to same domain (will likely block)
const sock1 = new SockJS('https://example.com/sockjs');
const sock2 = new SockJS('https://example.com/sockjs'); // May block
// DO: Use subdomains for multiple connections
const sock1 = new SockJS('https://api1.example.com/sockjs');
const sock2 = new SockJS('https://api2.example.com/sockjs');/**
* Security-related transport considerations
*/
const securityConsiderations = {
httpsToHttp: 'Blocked unless connecting to localhost/127.0.0.1',
xdrLimitations: 'No cookies, limited headers in IE 8-9',
jsonpSecurity: 'Script injection risks if server is compromised',
iframeSecurity: 'Same-origin policy bypass, use with trusted servers only'
};Secure Configuration Example:
// Secure configuration for production
const secureSock = new SockJS('https://secure-api.example.com/sockjs', null, {
// Avoid potentially insecure transports
transports: ['websocket', 'xhr-streaming', 'xhr-polling'],
// Enable credentials for authentication
transportOptions: {
'xhr-streaming': { withCredentials: true },
'xhr-polling': { withCredentials: true }
},
// Conservative timeout
timeout: 10000
});/**
* Transport performance characteristics (approximate)
*/
const performanceMetrics = {
'websocket': {
latency: 'Lowest (~1-10ms overhead)',
throughput: 'Highest',
resourceUsage: 'Lowest',
connectionSetup: 'Fast'
},
'xhr-streaming': {
latency: 'Low (~10-50ms overhead)',
throughput: 'High',
resourceUsage: 'Medium',
connectionSetup: 'Medium'
},
'xhr-polling': {
latency: 'Medium (~100-500ms)',
throughput: 'Medium',
resourceUsage: 'High',
connectionSetup: 'Fast'
},
'jsonp-polling': {
latency: 'Highest (~200-1000ms)',
throughput: 'Lowest',
resourceUsage: 'Highest',
connectionSetup: 'Slow'
}
};Install with Tessl CLI
npx tessl i tessl/npm-sockjs-client