Refactor WebSocket intro and create separate doc
Issue: SPR-15700
This commit is contained in:
95
src/docs/asciidoc/web/websocket-intro.adoc
Normal file
95
src/docs/asciidoc/web/websocket-intro.adoc
Normal file
@@ -0,0 +1,95 @@
|
||||
[[websocket-intro]]
|
||||
= Introduction
|
||||
|
||||
The WebSocket protocol http://tools.ietf.org/html/rfc6455[RFC 6455] provides a standardized
|
||||
way to establish a full-duplex, two-way communication channel between client and server
|
||||
over a single TCP connection. It is a different TCP protocol from HTTP but is designed to
|
||||
work over HTTP, using ports 80 and 443 and allowing re-use of existing firewall rules.
|
||||
|
||||
A WebSocket interaction begins with an HTTP request that uses the HTTP `"Upgrade"` header
|
||||
to upgrade, or in this case to switch, to the WebSocket protocol:
|
||||
|
||||
[subs="quotes"]
|
||||
----
|
||||
GET /spring-websocket-portfolio/portfolio HTTP/1.1
|
||||
Host: localhost:8080
|
||||
**Upgrade: websocket**
|
||||
**Connection: Upgrade**
|
||||
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
|
||||
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
|
||||
Sec-WebSocket-Version: 13
|
||||
Origin: http://localhost:8080
|
||||
----
|
||||
|
||||
Instead of the usual 200 status code, a server with WebSocket support returns:
|
||||
|
||||
[subs="quotes"]
|
||||
----
|
||||
**HTTP/1.1 101 Switching Protocols**
|
||||
Upgrade: websocket
|
||||
Connection: Upgrade
|
||||
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
|
||||
Sec-WebSocket-Protocol: v10.stomp
|
||||
----
|
||||
|
||||
After a successful handshake the TCP socket underlying the HTTP upgrade request remains
|
||||
open for both client and server to continue to send and receive messages.
|
||||
|
||||
A complete introduction of how WebSockets work is beyond the scope of this document.
|
||||
Please read RFC 6455, the WebSocket chapter of HTML5, or one of many introductions and
|
||||
tutorials on the Web.
|
||||
|
||||
Note that if a WebSocket server is running behind a web server (e.g. nginx) you will
|
||||
likely need to configure it to pass WebSocket upgrade requests on to the WebSocket
|
||||
server. Likewise if the application runs in a cloud environment, check the
|
||||
instructions of the cloud provider related to WebSocket support.
|
||||
|
||||
|
||||
|
||||
|
||||
[[websocket-intro-architecture]]
|
||||
== HTTP vs WebSocket
|
||||
|
||||
Even though WebSocket is designed to be HTTP compatible and starts with an HTTP request,
|
||||
it is important to understand that the two protocols lead to very different
|
||||
architectures and application programming models.
|
||||
|
||||
In HTTP and REST, an application is modeled as many URLs. To interact with the application
|
||||
clients access those URLs, request-response style. Servers route requests to the
|
||||
appropriate handler based on the HTTP URL, method, and headers.
|
||||
|
||||
By contrast in WebSockets there is usually just one URL for the initial connect and
|
||||
subsequently all application messages flow on that same TCP connection. This points to
|
||||
an entirely different asynchronous, event-driven, messaging architecture.
|
||||
|
||||
WebSocket is also a low-level transport protocol which unlike HTTP does not prescribe
|
||||
any semantics to the content of messages. That means there is no way to route or process
|
||||
a message unless client and server agree on message semantics.
|
||||
|
||||
WebSocket clients and servers can negotiate the use of a higher-level, messaging protocol
|
||||
(e.g. STOMP), via the `"Sec-WebSocket-Protocol"` header on the HTTP handshake request,
|
||||
or in the absence of that they need to come up with their own conventions.
|
||||
|
||||
|
||||
|
||||
[[websocket-intro-when-to-use]]
|
||||
== When to use it?
|
||||
|
||||
WebSockets can make a web page dynamic and interactive. However in many cases
|
||||
a combination of Ajax and HTTP streaming and/or long polling could provide a simple and
|
||||
effective solution.
|
||||
|
||||
For example news, mail, and social feeds need to update dynamically but it may be
|
||||
perfectly okay to do so every few minutes. Collaboration, games, and financial apps on
|
||||
the other hand need to be much closer to real time.
|
||||
|
||||
Latency alone is not a deciding factor. If the volume of messages is relatively low (e.g.
|
||||
monitoring network failures) HTTP streaming or polling may provide an effective solution.
|
||||
It is the combination of low latency, high frequency and high volume that make the best
|
||||
case for the use WebSocket.
|
||||
|
||||
Keep in mind also that over the Internet, restrictive proxies outside your control,
|
||||
may preclude WebSocket interactions either because they are not configured to pass on the
|
||||
`Upgrade` header or because they close long lived connections that appear idle? This
|
||||
means that the use of WebSocket for internal applications within the firewall is a more
|
||||
straight-forward decision than it is for public facing applications.
|
||||
@@ -2,163 +2,12 @@
|
||||
= WebSockets
|
||||
:doc-spring-security: {doc-root}/spring-security/site/docs/current/reference
|
||||
|
||||
This part of the reference documentation covers support for Servlet stack WebSocket
|
||||
messaging, SockJS-based fallback options, and the use of STOMP as a WebSocket messaging
|
||||
sub-protocol.
|
||||
|
||||
|
||||
|
||||
|
||||
[[websocket-intro]]
|
||||
== Introduction
|
||||
|
||||
The WebSocket protocol http://tools.ietf.org/html/rfc6455[RFC 6455] provides a standardized
|
||||
way to establish a full-duplex, two-way communication channel between client and server
|
||||
over a single TCP connection. It is a different TCP protocol from HTTP but is designed to
|
||||
work over HTTP ports 80 and 443 thus allowing use of existing firewall rules.
|
||||
|
||||
A WebSocket interaction begins with an HTTP compatible handshake request that uses the
|
||||
HTTP `"Upgrade"` header to request switching to the WebSocket protocol:
|
||||
|
||||
[subs="quotes"]
|
||||
----
|
||||
GET /spring-websocket-portfolio/portfolio HTTP/1.1
|
||||
Host: localhost:8080
|
||||
**Upgrade: websocket**
|
||||
**Connection: Upgrade**
|
||||
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
|
||||
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
|
||||
Sec-WebSocket-Version: 13
|
||||
Origin: http://localhost:8080
|
||||
----
|
||||
|
||||
The response from a server with WebSocket support:
|
||||
|
||||
[subs="quotes"]
|
||||
----
|
||||
**HTTP/1.1 101 Switching Protocols**
|
||||
Upgrade: websocket
|
||||
Connection: Upgrade
|
||||
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
|
||||
Sec-WebSocket-Protocol: v10.stomp
|
||||
----
|
||||
|
||||
After a successful handshake the TCP socket underlying the HTTP upgrade request remains
|
||||
open and both client and server can use send and receive messages.
|
||||
|
||||
If you Servlet container is running behind a web server (e.g. nginx) you will likely need
|
||||
to configure it to send WebSocket upgrades to the backend server. Likewise if running in a
|
||||
cloud environment check the instructions for WebSocket support of your cloud provider.
|
||||
|
||||
Beyond that, what do you do about restrictive proxies, outside your control, that preclude
|
||||
WebSocket interactions either because they are not configured to pass on the `Upgrade`
|
||||
header or because they close long lived connections that appear idle? The answer to this
|
||||
is WebSocket emulation that tries to use WebSocket first and then falls back HTTP-based
|
||||
techniques that WebSocket-like communication. See <<websocket-fallback>>.
|
||||
|
||||
|
||||
|
||||
|
||||
WebSocket brings up important design considerations that are important to recognize
|
||||
early on, especially in contrast to what we know about building web applications today.
|
||||
|
||||
Today REST is a widely accepted, understood, and supported
|
||||
architecture for building web applications. It is an architecture that relies
|
||||
on having many URLs (__nouns__), a handful of HTTP methods (__verbs__), and
|
||||
other principles such as using hypermedia (__links__), remaining stateless, etc.
|
||||
|
||||
By contrast a WebSocket application may use a single URL only for the
|
||||
initial HTTP handshake. All messages thereafter share and flow on the
|
||||
same TCP connection. This points to an entirely different, asynchronous,
|
||||
event-driven, messaging architecture. One that is much closer
|
||||
to traditional messaging applications (e.g. JMS, AMQP).
|
||||
|
||||
Spring Framework 4 includes a new `spring-messaging` module with key
|
||||
abstractions from the
|
||||
http://projects.spring.io/spring-integration/[Spring Integration] project
|
||||
such as `Message`, `MessageChannel`, `MessageHandler`, and others that can serve as
|
||||
a foundation for such a messaging architecture. The module also includes a
|
||||
set of annotations for mapping messages to methods, similar to the Spring MVC
|
||||
annotation based programming model.
|
||||
|
||||
|
||||
|
||||
[[websocket-intro-sub-protocol]]
|
||||
=== WebSocket Sub-Protocol
|
||||
|
||||
WebSocket does imply a __messaging architecture__ but does not mandate the
|
||||
use of any specific __messaging protocol__. It is a very thin layer over TCP
|
||||
that transforms a stream of bytes into a stream of messages
|
||||
(either text or binary) and not much more. It is up to applications
|
||||
to interpret the meaning of a message.
|
||||
|
||||
Unlike HTTP, which is an application-level protocol, in the WebSocket protocol
|
||||
there is simply not enough information in an incoming message for a framework
|
||||
or container to know how to route it or process it. Therefore WebSocket is arguably
|
||||
too low level for anything but a very trivial application. It can be done, but
|
||||
it will likely lead to creating a framework on top. This is comparable to how
|
||||
most web applications today are written using a web framework rather than the
|
||||
Servlet API alone.
|
||||
|
||||
For this reason the WebSocket RFC defines the use of
|
||||
http://tools.ietf.org/html/rfc6455#section-1.9[sub-protocols].
|
||||
During the handshake, the client and server can use the header
|
||||
`Sec-WebSocket-Protocol` to agree on a sub-protocol, i.e. a higher, application-level
|
||||
protocol to use. The use of a sub-protocol is not required, but
|
||||
even if not used, applications will still need to choose a message
|
||||
format that both the client and server can understand. That format can be custom,
|
||||
framework-specific, or a standard messaging protocol.
|
||||
|
||||
The Spring Framework provides support for using
|
||||
http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] -- a simple, messaging protocol
|
||||
originally created for use in scripting languages with frames inspired
|
||||
by HTTP. STOMP is widely supported and well suited for use over
|
||||
WebSocket and over the web.
|
||||
|
||||
|
||||
|
||||
[[websocket-intro-when-to-use]]
|
||||
=== Do I Use WebSocket?
|
||||
|
||||
With all the design considerations surrounding the use of WebSocket, it is
|
||||
reasonable to ask, "When is it appropriate to use?".
|
||||
|
||||
The best fit for WebSocket is in web applications where the client and
|
||||
server need to exchange events at high frequency and with low latency. Prime
|
||||
candidates include, but are not limited to, applications in finance, games,
|
||||
collaboration, and others. Such applications are both very sensitive to time
|
||||
delays and also need to exchange a wide variety of messages at a high
|
||||
frequency.
|
||||
|
||||
For other application types, however, this may not be the case.
|
||||
For example, a news or social feed that shows breaking news as it becomes
|
||||
available may be perfectly okay with simple polling once every few minutes.
|
||||
Here latency is important, but it is acceptable if the news takes a
|
||||
few minutes to appear.
|
||||
|
||||
Even in cases where latency is crucial, if the volume of messages is
|
||||
relatively low (e.g. monitoring network failures) the use of
|
||||
https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates[long polling]
|
||||
should be considered as a relatively simple alternative that
|
||||
works reliably and is comparable in terms of efficiency (again assuming the volume of
|
||||
messages is relatively low).
|
||||
|
||||
It is the combination of both low latency and high frequency of messages that can make
|
||||
the use of the WebSocket protocol critical. Even in such applications,
|
||||
the choice remains whether all client-server
|
||||
communication should be done through WebSocket messages as opposed to using
|
||||
HTTP and REST. The answer is going to vary by application; however, it is likely
|
||||
that some functionality may be exposed over both WebSocket and as a REST API in
|
||||
order to provide clients with alternatives. Furthermore, a REST API call may need
|
||||
to broadcast a message to interested clients connected via WebSocket.
|
||||
|
||||
The Spring Framework allows `@Controller` and `@RestController` classes to have both
|
||||
HTTP request handling and WebSocket message handling methods.
|
||||
Furthermore, a Spring MVC request handling method, or any application
|
||||
method for that matter, can easily broadcast a message to all interested
|
||||
WebSocket clients or to a specific user.
|
||||
This part of the reference documentation covers support for Servlet stack, WebSocket
|
||||
messaging that includes raw WebSocket interactions, WebSocket emulation via SockJS, and
|
||||
pub-sub messaging via STOMP as a sub-protocol over WebSocket.
|
||||
|
||||
|
||||
include::websocket-intro.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
[[websocket-server]]
|
||||
@@ -620,12 +469,16 @@ XML configuration equivalent:
|
||||
[[websocket-fallback]]
|
||||
== SockJS Fallback
|
||||
|
||||
As explained in the <<websocket-into-fallback-options,introduction>>, WebSocket is not
|
||||
supported in all browsers yet and may be precluded by restrictive network proxies.
|
||||
This is why Spring provides fallback options that emulate the WebSocket API as close
|
||||
as possible based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol]
|
||||
(version 0.3.3).
|
||||
Over the public Internet, restrictive proxies outside your control may preclude WebSocket
|
||||
interactions either because they are not configured to pass on the `Upgrade` header or
|
||||
because they close long lived connections that appear idle.
|
||||
|
||||
The solution to this problem is WebSocket emulation, i.e. attempting to use WebSocket
|
||||
first and then falling back on HTTP-based techniques that emulate a WebSocket
|
||||
interaction and expose the same application-level API.
|
||||
|
||||
On the Servlet stack the Spring Framework provides both server (and also client) support
|
||||
for the SockJS protocol.
|
||||
|
||||
|
||||
[[websocket-fallback-sockjs-overview]]
|
||||
|
||||
Reference in New Issue
Block a user