0
# SockJS Support
1
2
SockJS fallback support providing WebSocket-like object in browsers that don't support WebSocket natively, with multiple transport options.
3
4
## Capabilities
5
6
### SockJS Service Interface
7
8
Main contract for processing SockJS HTTP requests with fallback transport support.
9
10
```java { .api }
11
/**
12
* Main contract for processing SockJS HTTP requests.
13
* Handles protocol negotiation and transport selection for SockJS connections.
14
*/
15
interface SockJsService {
16
/**
17
* Handle SockJS request with appropriate transport.
18
* @param request HTTP request
19
* @param response HTTP response
20
* @param sockJsPath SockJS endpoint path
21
* @param webSocketHandler WebSocket handler for the connection
22
* @throws SockJsException if request processing fails
23
*/
24
void handleRequest(
25
ServerHttpRequest request,
26
ServerHttpResponse response,
27
String sockJsPath,
28
WebSocketHandler webSocketHandler
29
) throws SockJsException;
30
31
/**
32
* Get the welcome message for info requests.
33
* @return welcome message string
34
*/
35
String getWelcomeMessage();
36
37
/**
38
* Check if origin validation is enabled.
39
* @return true if origin validation is enabled
40
*/
41
boolean getAllowedOrigins();
42
}
43
```
44
45
### Transport Types
46
47
Enumeration of available SockJS transport types for fallback scenarios.
48
49
```java { .api }
50
/**
51
* Enumeration of SockJS transport types.
52
* Provides different fallback mechanisms for WebSocket connections.
53
*/
54
enum TransportType {
55
/**
56
* Native WebSocket transport (preferred).
57
*/
58
WEBSOCKET,
59
60
/**
61
* XMLHttpRequest transport for sending data.
62
*/
63
XHR,
64
65
/**
66
* XMLHttpRequest send transport for one-way data sending.
67
*/
68
XHR_SEND,
69
70
/**
71
* XMLHttpRequest streaming transport for real-time data.
72
*/
73
XHR_STREAMING,
74
75
/**
76
* Server-Sent Events transport for real-time data.
77
*/
78
EVENT_SOURCE,
79
80
/**
81
* HTML file transport using hidden iframe.
82
*/
83
HTML_FILE;
84
85
/**
86
* Get the transport type from string value.
87
* @param value string representation of transport type
88
* @return corresponding TransportType
89
*/
90
public static TransportType fromValue(String value);
91
92
/**
93
* Get the string value of this transport type.
94
* @return string representation
95
*/
96
public String value();
97
98
/**
99
* Get the HTTP method used by this transport.
100
* @return HTTP method (GET or POST)
101
*/
102
public HttpMethod getHttpMethod();
103
104
/**
105
* Check if this transport sends no-cache instructions.
106
* @return true if no-cache headers are sent
107
*/
108
public boolean sendsNoCacheInstruction();
109
110
/**
111
* Check if this transport sends session cookies.
112
* @return true if session cookies are sent
113
*/
114
public boolean sendsSessionCookie();
115
116
/**
117
* Check if this transport supports CORS.
118
* @return true if CORS is supported
119
*/
120
public boolean supportsCors();
121
122
/**
123
* Check if this transport supports Origin header.
124
* @return true if Origin header is supported
125
*/
126
public boolean supportsOrigin();
127
}
128
```
129
130
### SockJS Session Interface
131
132
SockJS session abstraction extending WebSocketSession with SockJS-specific features.
133
134
```java { .api }
135
/**
136
* SockJS session abstraction extending WebSocketSession.
137
* Provides SockJS-specific session management and transport handling.
138
*/
139
interface SockJsSession extends WebSocketSession {
140
/**
141
* Get the unique session identifier.
142
* @return session ID
143
*/
144
String getId();
145
146
/**
147
* Close the SockJS session.
148
* @throws IOException if closing fails
149
*/
150
void close() throws IOException;
151
152
/**
153
* Close the SockJS session with specific status.
154
* @param status close status
155
* @throws IOException if closing fails
156
*/
157
void close(CloseStatus status) throws IOException;
158
}
159
```
160
161
### SockJS Configuration
162
163
Configuration interfaces and classes for customizing SockJS behavior.
164
165
```java { .api }
166
/**
167
* Configuration interface for SockJS services.
168
* Provides settings for timeouts, limits, and transport options.
169
*/
170
interface SockJsServiceConfig {
171
/**
172
* Get the streaming bytes limit before reconnection.
173
* @return bytes limit for streaming transports
174
*/
175
int getStreamBytesLimit();
176
177
/**
178
* Get the heartbeat interval in milliseconds.
179
* @return heartbeat time
180
*/
181
long getHeartbeatTime();
182
183
/**
184
* Get the task scheduler for SockJS operations.
185
* @return task scheduler instance
186
*/
187
TaskScheduler getTaskScheduler();
188
189
/**
190
* Get the message codec for frame encoding/decoding.
191
* @return message codec instance
192
*/
193
MessageCodec getMessageCodec();
194
}
195
196
/**
197
* Factory interface for creating SockJS sessions.
198
*/
199
interface SockJsSessionFactory {
200
/**
201
* Create a new SockJS session.
202
* @param sessionId unique session identifier
203
* @param handler WebSocket handler for the session
204
* @param attributes session attributes
205
* @return new SockJS session instance
206
*/
207
SockJsSession createSession(
208
String sessionId,
209
WebSocketHandler handler,
210
Map<String, Object> attributes
211
);
212
}
213
```
214
215
### Default SockJS Service
216
217
Default implementation of SockJS service with pre-configured transport handlers.
218
219
```java { .api }
220
/**
221
* Default SockJS service implementation with pre-configured transports.
222
* Supports all standard SockJS transport types.
223
*/
224
class DefaultSockJsService extends AbstractSockJsService {
225
/**
226
* Create default SockJS service with task scheduler.
227
* @param scheduler task scheduler for SockJS operations
228
*/
229
public DefaultSockJsService(TaskScheduler scheduler);
230
231
/**
232
* Set whether to enable WebSocket transport.
233
* @param webSocketEnabled true to enable WebSocket
234
*/
235
public void setWebSocketEnabled(boolean webSocketEnabled);
236
237
/**
238
* Check if WebSocket transport is enabled.
239
* @return true if WebSocket is enabled
240
*/
241
public boolean isWebSocketEnabled();
242
243
/**
244
* Set the session cookie needed indicator.
245
* @param sessionCookieNeeded true if session cookie is needed
246
*/
247
public void setSessionCookieNeeded(boolean sessionCookieNeeded);
248
249
/**
250
* Check if session cookie is needed.
251
* @return true if session cookie is needed
252
*/
253
public boolean isSessionCookieNeeded();
254
255
/**
256
* Set the heartbeat time in milliseconds.
257
* @param heartbeatTime heartbeat interval
258
*/
259
public void setHeartbeatTime(long heartbeatTime);
260
261
/**
262
* Get the heartbeat time.
263
* @return heartbeat interval in milliseconds
264
*/
265
public long getHeartbeatTime();
266
267
/**
268
* Set the disconnect delay in milliseconds.
269
* @param disconnectDelay delay before closing inactive sessions
270
*/
271
public void setDisconnectDelay(long disconnectDelay);
272
273
/**
274
* Get the disconnect delay.
275
* @return disconnect delay in milliseconds
276
*/
277
public long getDisconnectDelay();
278
279
/**
280
* Set the streaming bytes limit.
281
* @param streamBytesLimit bytes limit for streaming transports
282
*/
283
public void setStreamBytesLimit(int streamBytesLimit);
284
285
/**
286
* Get the streaming bytes limit.
287
* @return bytes limit for streaming transports
288
*/
289
public int getStreamBytesLimit();
290
}
291
```
292
293
**Usage Example:**
294
295
```java
296
@Configuration
297
@EnableWebSocket
298
public class SockJsConfig implements WebSocketConfigurer {
299
300
@Bean
301
public TaskScheduler sockJsTaskScheduler() {
302
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
303
scheduler.setPoolSize(10);
304
scheduler.setThreadNamePrefix("SockJS-");
305
scheduler.initialize();
306
return scheduler;
307
}
308
309
@Override
310
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
311
// Register handler with SockJS support
312
registry.addHandler(new ChatWebSocketHandler(), "/chat")
313
.withSockJS()
314
.setHeartbeatTime(25000) // 25 second heartbeat
315
.setDisconnectDelay(5000) // 5 second disconnect delay
316
.setStreamBytesLimit(128 * 1024) // 128KB streaming limit
317
.setSessionCookieNeeded(false) // No session cookie required
318
.setClientLibraryUrl("https://cdn.jsdelivr.net/npm/sockjs-client@1.6.1/dist/sockjs.min.js")
319
.setTransportHandlers(customTransportHandlers())
320
.setAllowedOrigins("*");
321
}
322
323
private List<TransportHandler> customTransportHandlers() {
324
List<TransportHandler> handlers = new ArrayList<>();
325
326
// Enable/disable specific transports
327
handlers.add(new WebSocketTransportHandler(handshakeHandler()));
328
handlers.add(new XhrPollingTransportHandler());
329
handlers.add(new XhrStreamingTransportHandler());
330
handlers.add(new JsonpPollingTransportHandler());
331
handlers.add(new EventSourceTransportHandler());
332
handlers.add(new HtmlFileTransportHandler());
333
334
return handlers;
335
}
336
337
@Bean
338
public DefaultSockJsService sockJsService() {
339
DefaultSockJsService service = new DefaultSockJsService(sockJsTaskScheduler());
340
341
service.setWebSocketEnabled(true);
342
service.setHeartbeatTime(25000);
343
service.setDisconnectDelay(5000);
344
service.setStreamBytesLimit(128 * 1024);
345
service.setSessionCookieNeeded(false);
346
347
return service;
348
}
349
}
350
```
351
352
### SockJS Transport Handlers
353
354
Transport handler implementations for different SockJS transport types.
355
356
```java { .api }
357
/**
358
* Contract for handling SockJS transport requests.
359
* Implementations handle specific transport protocols.
360
*/
361
interface TransportHandler {
362
/**
363
* Get the transport type handled by this handler.
364
* @return transport type
365
*/
366
TransportType getTransportType();
367
368
/**
369
* Check if the handler supports the given session type.
370
* @param session SockJS session
371
* @return true if session type is supported
372
*/
373
boolean checkSessionType(SockJsSession session);
374
375
/**
376
* Handle transport request.
377
* @param request HTTP request
378
* @param response HTTP response
379
* @param webSocketHandler WebSocket handler
380
* @param sockJsSession SockJS session
381
* @throws SockJsException if handling fails
382
*/
383
void handleRequest(
384
ServerHttpRequest request,
385
ServerHttpResponse response,
386
WebSocketHandler webSocketHandler,
387
SockJsSession sockJsSession
388
) throws SockJsException;
389
}
390
391
/**
392
* Transport handler for WebSocket transport.
393
*/
394
class WebSocketTransportHandler implements TransportHandler {
395
/**
396
* Create WebSocket transport handler.
397
* @param handshakeHandler handshake handler for WebSocket upgrade
398
*/
399
public WebSocketTransportHandler(HandshakeHandler handshakeHandler);
400
}
401
402
/**
403
* Transport handler for XHR polling.
404
*/
405
class XhrPollingTransportHandler extends AbstractHttpSendingTransportHandler {
406
public XhrPollingTransportHandler();
407
}
408
409
/**
410
* Transport handler for XHR streaming.
411
*/
412
class XhrStreamingTransportHandler extends AbstractHttpSendingTransportHandler {
413
public XhrStreamingTransportHandler();
414
}
415
416
/**
417
* Transport handler for Server-Sent Events.
418
*/
419
class EventSourceTransportHandler extends AbstractHttpSendingTransportHandler {
420
public EventSourceTransportHandler();
421
}
422
423
/**
424
* Transport handler for HTML file transport.
425
*/
426
class HtmlFileTransportHandler extends AbstractHttpSendingTransportHandler {
427
public HtmlFileTransportHandler();
428
}
429
430
/**
431
* Transport handler for JSONP polling.
432
*/
433
class JsonpPollingTransportHandler extends AbstractHttpSendingTransportHandler {
434
public JsonpPollingTransportHandler();
435
}
436
437
/**
438
* Transport handler for receiving XHR messages.
439
*/
440
class XhrReceivingTransportHandler extends AbstractHttpReceivingTransportHandler {
441
public XhrReceivingTransportHandler();
442
}
443
```
444
445
### SockJS Frame Handling
446
447
Frame format and message codec interfaces for SockJS protocol.
448
449
```java { .api }
450
/**
451
* Contract for formatting SockJS frames for transport.
452
*/
453
interface SockJsFrameFormat {
454
/**
455
* Format a SockJS frame for the specific transport.
456
* @param frame SockJS frame to format
457
* @return formatted frame string
458
*/
459
String format(SockJsFrame frame);
460
}
461
462
/**
463
* Contract for encoding and decoding SockJS messages.
464
*/
465
interface SockJsMessageCodec {
466
/**
467
* Encode messages into SockJS frame format.
468
* @param messages array of message strings
469
* @return encoded frame content
470
* @throws IOException if encoding fails
471
*/
472
String encode(String... messages) throws IOException;
473
474
/**
475
* Decode SockJS frame content into messages.
476
* @param content encoded frame content
477
* @return array of decoded messages
478
* @throws IOException if decoding fails
479
*/
480
String[] decode(String content) throws IOException;
481
482
/**
483
* Decode SockJS frame content from input stream.
484
* @param content input stream with encoded content
485
* @return array of decoded messages
486
* @throws IOException if decoding fails
487
*/
488
String[] decodeInputStream(InputStream content) throws IOException;
489
}
490
491
/**
492
* Represents a SockJS frame with type and content.
493
*/
494
class SockJsFrame {
495
/**
496
* Create an open frame.
497
* @return open frame instance
498
*/
499
public static SockJsFrame openFrame();
500
501
/**
502
* Create a heartbeat frame.
503
* @return heartbeat frame instance
504
*/
505
public static SockJsFrame heartbeatFrame();
506
507
/**
508
* Create a message frame with encoded messages.
509
* @param codec message codec for encoding
510
* @param messages messages to include
511
* @return message frame instance
512
*/
513
public static SockJsFrame messageFrame(MessageCodec codec, String... messages);
514
515
/**
516
* Create a close frame with status and reason.
517
* @param code close status code
518
* @param reason close reason
519
* @return close frame instance
520
*/
521
public static SockJsFrame closeFrame(int code, String reason);
522
523
/**
524
* Get the frame type.
525
* @return frame type
526
*/
527
public SockJsFrameType getType();
528
529
/**
530
* Get the frame content.
531
* @return frame content string
532
*/
533
public String getContent();
534
}
535
536
/**
537
* Enumeration of SockJS frame types.
538
*/
539
enum SockJsFrameType {
540
/**
541
* Connection opened frame.
542
*/
543
OPEN,
544
545
/**
546
* Heartbeat frame for keep-alive.
547
*/
548
HEARTBEAT,
549
550
/**
551
* Message frame containing data.
552
*/
553
MESSAGE,
554
555
/**
556
* Connection closed frame.
557
*/
558
CLOSE
559
}
560
561
/**
562
* Default implementation of SockJsFrameFormat.
563
*/
564
class DefaultSockJsFrameFormat implements SockJsFrameFormat {
565
public DefaultSockJsFrameFormat();
566
}
567
568
/**
569
* SockJS message codec using Jackson 2 for JSON processing.
570
*/
571
class Jackson2SockJsMessageCodec extends AbstractSockJsMessageCodec {
572
public Jackson2SockJsMessageCodec();
573
}
574
```
575
576
### SockJS Client Support
577
578
Client-side SockJS implementation for connecting to SockJS-enabled servers.
579
580
```java { .api }
581
/**
582
* Main SockJS client implementation.
583
* Provides automatic transport fallback for unreliable connections.
584
*/
585
class SockJsClient implements WebSocketClient {
586
/**
587
* Create SockJS client with transport list.
588
* @param transports list of transport implementations
589
*/
590
public SockJsClient(List<Transport> transports);
591
592
/**
593
* Set the message codec for frame processing.
594
* @param messageCodec codec instance
595
*/
596
public void setMessageCodec(SockJsMessageCodec messageCodec);
597
598
/**
599
* Get the message codec.
600
* @return codec instance
601
*/
602
public SockJsMessageCodec getMessageCodec();
603
604
/**
605
* Set the info receiver for server capability detection.
606
* @param infoReceiver info receiver implementation
607
*/
608
public void setInfoReceiver(InfoReceiver infoReceiver);
609
610
/**
611
* Get the info receiver.
612
* @return info receiver implementation
613
*/
614
public InfoReceiver getInfoReceiver();
615
}
616
617
/**
618
* Contract for SockJS client transport implementations.
619
*/
620
interface Transport {
621
/**
622
* Connect using this transport.
623
* @param request transport request information
624
* @param handler WebSocket handler for the connection
625
* @return future that completes when connected
626
*/
627
ListenableFuture<WebSocketSession> connect(
628
TransportRequest request,
629
WebSocketHandler handler
630
);
631
632
/**
633
* Get transport type.
634
* @return transport type
635
*/
636
TransportType getTransportType();
637
}
638
639
/**
640
* SockJS client WebSocket transport implementation.
641
*/
642
class WebSocketTransport implements Transport {
643
/**
644
* Create WebSocket transport with client.
645
* @param webSocketClient underlying WebSocket client
646
*/
647
public WebSocketTransport(WebSocketClient webSocketClient);
648
}
649
650
/**
651
* XHR transport implementation using RestTemplate.
652
*/
653
class RestTemplateXhrTransport extends AbstractXhrTransport {
654
/**
655
* Create XHR transport with RestTemplate.
656
*/
657
public RestTemplateXhrTransport();
658
659
/**
660
* Create XHR transport with custom RestTemplate.
661
* @param restTemplate configured RestTemplate instance
662
*/
663
public RestTemplateXhrTransport(RestTemplate restTemplate);
664
}
665
```
666
667
**Usage Example:**
668
669
```java
670
@Service
671
public class SockJsClientService {
672
673
private final SockJsClient sockJsClient;
674
675
public SockJsClientService() {
676
// Configure transports in preference order
677
List<Transport> transports = Arrays.asList(
678
new WebSocketTransport(new StandardWebSocketClient()),
679
new RestTemplateXhrTransport(),
680
new JettyXhrTransport()
681
);
682
683
this.sockJsClient = new SockJsClient(transports);
684
this.sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec());
685
}
686
687
public CompletableFuture<WebSocketSession> connectToChat(String serverUrl) {
688
WebSocketHandler handler = new ChatClientHandler();
689
690
ListenableFuture<WebSocketSession> future = sockJsClient.doHandshake(
691
handler,
692
serverUrl + "/chat"
693
);
694
695
return toCompletableFuture(future);
696
}
697
698
public CompletableFuture<WebSocketSession> connectWithAuth(String serverUrl, String token) {
699
WebSocketHandler handler = new AuthenticatedClientHandler(token);
700
701
WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
702
headers.add("Authorization", "Bearer " + token);
703
704
ListenableFuture<WebSocketSession> future = sockJsClient.doHandshake(
705
handler,
706
headers,
707
URI.create(serverUrl + "/secure-chat")
708
);
709
710
return toCompletableFuture(future);
711
}
712
}
713
714
// Client handler with SockJS transport fallback awareness
715
public class ChatClientHandler extends AbstractWebSocketHandler {
716
717
@Override
718
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
719
logger.info("Connected via transport: {}", getTransportType(session));
720
session.sendMessage(new TextMessage("Hello from SockJS client!"));
721
}
722
723
@Override
724
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
725
String payload = message.getPayload();
726
logger.info("Received: {}", payload);
727
728
// Echo message back
729
session.sendMessage(new TextMessage("Echo: " + payload));
730
}
731
732
@Override
733
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
734
logger.error("Transport error ({}): {}",
735
getTransportType(session), exception.getMessage());
736
737
// SockJS client will automatically try fallback transports
738
}
739
740
private String getTransportType(WebSocketSession session) {
741
// Try to determine actual transport used
742
if (session instanceof NativeWebSocketSession nativeSession) {
743
Object nativeSessionObj = nativeSession.getNativeSession();
744
return nativeSessionObj.getClass().getSimpleName();
745
}
746
return "unknown";
747
}
748
}
749
```
750
751
### SockJS Exception Classes
752
753
Exception hierarchy for SockJS-related errors.
754
755
```java { .api }
756
/**
757
* Base exception for SockJS-related errors.
758
*/
759
class SockJsException extends Exception {
760
/**
761
* Create SockJS exception with message.
762
* @param message error message
763
*/
764
public SockJsException(String message);
765
766
/**
767
* Create SockJS exception with message and cause.
768
* @param message error message
769
* @param cause underlying cause
770
*/
771
public SockJsException(String message, Throwable cause);
772
}
773
774
/**
775
* Exception for SockJS transport failures.
776
*/
777
class SockJsTransportFailureException extends SockJsException {
778
/**
779
* Create transport failure exception.
780
* @param message error message
781
* @param cause underlying cause
782
*/
783
public SockJsTransportFailureException(String message, Throwable cause);
784
}
785
786
/**
787
* Exception for SockJS message delivery failures.
788
*/
789
class SockJsMessageDeliveryException extends SockJsException {
790
/**
791
* Create message delivery exception.
792
* @param message error message
793
*/
794
public SockJsMessageDeliveryException(String message);
795
}
796
```