Skip to content

Commit 84133c8

Browse files
committed
Update SockJS overview section and polish
1 parent 90512f0 commit 84133c8

File tree

1 file changed

+70
-54
lines changed

1 file changed

+70
-54
lines changed

src/asciidoc/index.adoc

Lines changed: 70 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -37195,6 +37195,64 @@ supported in all browsers yet and may be precluded by restrictive network proxie
3719537195
This is why Spring provides fallback options that emulate the WebSocket API as close
3719637196
as possible based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol].
3719737197

37198+
[[websocket-fallback-sockjs-overview]]
37199+
==== Overview of SockJS
37200+
37201+
The goal of SockJS is to let applications use a WebSocket API but fall back to
37202+
non-WebSocket alternatives when necessary at runtime, i.e. without the need to
37203+
change application code.
37204+
37205+
SockJS consists of:
37206+
37207+
* The https://github.com/sockjs/sockjs-protocol[SockJS protocol]
37208+
defined in the form of executable
37209+
http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated tests].
37210+
* The https://github.com/sockjs/sockjs-client[SockJS client] - a JavaScript library for use in browsers.
37211+
* SockJS server implementations including one in the Spring Framework `spring-websocket` module.
37212+
37213+
SockJS is designed for use in browsers. It goes to great lengths
37214+
to support a wide range of browser versions using a variety of techniques.
37215+
For the full list of SockJS transport types and browsers see the
37216+
https://github.com/sockjs/sockjs-client[SockJS client] page. Transports
37217+
fall in 3 general categories: WebSocket, HTTP Streaming, and HTTP Long Polling.
37218+
For an overview of these categories see
37219+
https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/[this blog post].
37220+
37221+
The SockJS client begins by sending `"GET /info"` to
37222+
obtain basic information from the server. After that it must decide what transport
37223+
to use. If possible WebSocket is used. If not, in most browsers
37224+
there is at least one HTTP streaming option and if not then HTTP (long)
37225+
polling is used.
37226+
37227+
All transport requests have the following URL structure:
37228+
----
37229+
http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}
37230+
----
37231+
37232+
* `{server-id}` - useful for routing requests in a cluster but not used otherwise.
37233+
* `{session-id}` - correlates HTTP requests belonging to a SockJS session.
37234+
* `{transport}` - indicates the transport type, e.g. "websocket", "xhr-streaming", etc.
37235+
37236+
The WebSocket transport needs only a single HTTP request to do the WebSocket handshake.
37237+
All messages thereafter are exchanged on that socket.
37238+
37239+
HTTP transports require more requests. Ajax/XHR streaming for example relies on
37240+
one long-running request for server-to-client messages and additional HTTP POST
37241+
requests for client-to-server messages. Long polling is similar except it
37242+
ends the current request after each server-to-client send.
37243+
37244+
SockJS adds minimal message framing. For example the server sends the letter +o+
37245+
("open" frame) initially, messages are sent as +a["message1","message2"]+
37246+
(JSON-encoded array), the letter +h+ ("heartbeat" frame) if no messages flow
37247+
for 25 seconds by default, and the letter +c+ ("close" frame) to close the session.
37248+
37249+
To learn more run an example in a browser and watch HTTP requests.
37250+
The SockJS client allows fixing the list of transports so it is possible to
37251+
see each transport one at a time. The SockJS client also provides a debug flag
37252+
which enables helpful messages in the browser console. On the server side enable
37253+
TRACE logging for `org.springframework.web.socket`.
37254+
For even more detail refer to the SockJS protocol
37255+
http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated test].
3719837256

3719937257

3720037258
[[websocket-fallback-sockjs-enable]]
@@ -37259,22 +37317,6 @@ https://github.com/sockjs/sockjs-client[sockjs-client] page and the list of
3725937317
transport types supported by browser. The client also provides several
3726037318
configuration options, for example, to specify which transports to include.
3726137319

37262-
[[websocket-fallback-sockjs-transport]]
37263-
==== SockJS Transports
37264-
37265-
The SockJS client simulates the WebSocket API in a wide range of browsers.
37266-
For the full list of transports by browser see the
37267-
https://github.com/sockjs/sockjs-client[SockJS client] page. The transport types
37268-
fall in 3 categories: WebSocket, HTTP Streaming, and HTTP Long Polling. For more
37269-
background on those techniques see
37270-
https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/[this blog post].
37271-
An important goal of SockJS is to support at least one streaming transport
37272-
per browser, for efficiency reasons, but when necessary fall back on
37273-
long polling.
37274-
37275-
The next few sections cover various aspects of confugring and using SockJS
37276-
in Spring applications.
37277-
3727837320
[[websocket-fallback-xhr-vs-iframe]]
3727937321
==== HTTP Streaming in IE 8, 9: Ajax/XHR vs IFrame
3728037322

@@ -37357,7 +37399,7 @@ https://github.com/sockjs/sockjs-client[SockJS client] page.
3735737399
====
3735837400

3735937401
[[websocket-fallback-sockjs-heartbeat]]
37360-
==== Heartbeat Support in SockJS
37402+
==== Heartbeat Messages
3736137403

3736237404
The SockJS protocol requires servers to send heartbeat messages to preclude proxies
3736337405
from concluding a connection is hung. The Spring SockJS configuiration has a property
@@ -37378,7 +37420,7 @@ with default settings based on the number of available processors. Applications
3737837420
should consider customizing the settings according to their specific needs.
3737937421

3738037422
[[websocket-fallback-sockjs-servlet3-async]]
37381-
==== SockJS and Servlet 3 Async Support
37423+
==== Servlet 3 Async Requests
3738237424

3738337425
HTTP streaming and HTTP long polling SockJS transports require a connection to remain
3738437426
open longer than usual. For an overview of these techniques see
@@ -37406,53 +37448,27 @@ log category to TRACE.
3740637448
====
3740737449

3740837450
[[websocket-fallback-cors]]
37409-
==== SockJS and CORS
37451+
==== CORS Headers for SockJS Requests
3741037452

3741137453
The SockJS protocol uses CORS for cross-domain support in the XHR streaming and
37412-
XHR polling transports. CORS headers are automatically added to SockJS requests
37413-
for transports that require it as well as for the initial `"/info"` request.
37454+
polling transports. Therefore CORS headers are added automatically unless the
37455+
presence of CORS headers in the response is detected. So if an application is
37456+
already configured to provide CORS support, e.g. through a Servlet Filter,
37457+
Spring's SockJsService will skip this part.
3741437458

37415-
Spring's `SockJsServce` implementation checks for the presence of the CORS
37416-
`"Access-Control-Allow-Origin"` header in the response. If present, no new CORS
37417-
headers are added, essentially assuming that CORS support is configured
37418-
centrally, e.g. through a Servlet Filter. Otherwise the following are added:
37459+
The following is the list of headers and values expected by SockJS:
3741937460

3742037461
* `"Access-Control-Allow-Origin"` - intitialized from the value of the "origin" request header or "*".
3742137462
* `"Access-Control-Allow-Credentials"` - always set to `true`.
3742237463
* `"Access-Control-Request-Headers"` - initialized from values from the equivalent request header.
3742337464
* `"Access-Control-Allow-Methods"` - the HTTP methods a transport supports (see `TransportType` enum).
3742437465
* `"Access-Control-Max-Age"` - set to 31536000 (1 year).
3742537466

37426-
For the exact implementation, see `addCorsHeaders` in `AbstractSockJsService`.
37427-
37428-
[[websocket-fallback-sockjs-explained]]
37429-
==== How SockJS Works
37430-
This is a question beyond the scope of this document. The SockJS protocol
37431-
is defined in the form of a Python
37432-
https://github.com/sockjs/sockjs-protocol/blob/master/sockjs-protocol-0.3.3.py[test suite],
37433-
with narrative in comments. There is an
37434-
http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[HTML formatted version]
37435-
of the test showing narrative on the right and client code on the left.
37436-
37437-
The SockJS client begins with an initial `"/info"` request to obtain basic
37438-
information from the server. Then the client selects a transport and sends
37439-
a series of session requests:
37440-
37441-
----
37442-
http://host:port/{sockjs-endpoint}/{server-id}/{session-id}/{transport}
37443-
----
37444-
37445-
The WebSocket transport type only needs a single HTTP connection for the handshake.
37446-
HTTP-based transports use one connection for sending messages from server to client
37447-
and separate requests for sending messages from client to server.
37448-
The session id is used to correlate HTTP requests belonging to the same SockJS
37449-
session. The server id is not used in the protocol but is added to help in
37450-
clustered environments.
37467+
For the exact implementation see `addCorsHeaders` in `AbstractSockJsService` as well
37468+
as the `TransportType` enum in the source code.
3745137469

37452-
The SockJS protocol requires minimal message framing. The server for examples sends
37453-
an "open frame" (the letter +o+), a "heartbeat frame" (the letter +h+), or a
37454-
"close frame" (the letter +c+); while the client sends messages as a JSON-encoded
37455-
array prepended with the letter `a` (e.g. +a["message1","message2"]+).
37470+
Alternatively if the CORS configuration allows it consider excluding URLs with the
37471+
SockJS endpoint prefix thus letting Spring's SockJsService handle it.
3745637472

3745737473

3745837474
[[websocket-stomp]]

0 commit comments

Comments
 (0)