REST vs WebSockets – REST与WebSockets

最后修改: 2019年 4月 10日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll go through the basics of client-server communication and explore this through two popular options available today. We’ll see how WebSocket, which is a new entrant, fares against the more popular choice of RESTful HTTP.

在本教程中,我们将了解客户机-服务器通信的基本知识,并通过当今两种流行的选择进行探讨。我们将看看作为新加入者的WebSocket在与更受欢迎的RESTful HTTP的竞争中表现如何。

2. Basics of Network Communication

2.网络通信的基础知识

Before we deep-dive into the details of different options and their merits and demerits, let’s quickly refresh the landscape of network communication. This will help to put things in perspective and understand this better.

在我们深入探讨不同选项的细节及其优缺点之前,让我们快速刷新一下网络通信的面貌。这将有助于把事情看清楚,更好地理解这一点。

Network communications can be best understood in terms of the Open Systems Interconnection (OSI) model.

开放系统互连(OSI)模型来看,可以最好地理解网络通信。

OSI model partitions the communication system into seven layers of abstraction:

OSI模型将通信系统划分为七个抽象层:

OCI-Model

At the top of this model is the Application layer which is of our interest in this tutorial. However, we’ll discuss some aspects in the top four layers as we go along comparing WebSocket and RESTful HTTP.

在这个模型的顶部是应用层,这是我们在本教程中感兴趣的。不过,在比较WebSocket和RESTful HTTP的过程中,我们将讨论前四层的一些问题。

The application layer is closest to the end user and is responsible for interfacing with the applications participating in the communication. There are several popular protocols which are used in this layer like FTP, SMTP, SNMP, HTTP, and WebSocket.

应用层最接近最终用户,负责与参与通信的应用程序对接。有几个流行的协议被用于该层,如FTP、SMTP、SNMP、HTTP和WebSocket。

3. Describing WebSocket and RESTful HTTP

3.描述WebSocket和RESTful HTTP

While communication can happen between any number of systems, we are particularly interested in client-server communication. More specifically, we’ll focus on communication between a web browser and a web server. This is the frame we’ll use to compare WebSocket with RESTful HTTP.

虽然通信可以发生在任何数量的系统之间,但我们对客户-服务器通信特别感兴趣。更具体地说,我们将专注于网络浏览器和网络服务器之间的通信。这就是我们用来比较WebSocket与RESTful HTTP的框架。

But before we proceed any further, why not quickly understand what they are!

但在我们进一步开展工作之前,为什么不迅速了解它们是什么呢!?

3.1. WebSockets

3.1 WebSockets

As the formal definition goes, WebSocket is a communication protocol which features bi-directional, full-duplex communication over a persistent TCP connection. Now, we’ll understand each part of this statement in detail as we go along.

按照正式的定义,WebSocket是一种通信协议,其特点是通过持久的TCP连接进行双向、全双工通信。现在,我们将在接下来的时间里详细了解这一声明的每个部分。

 

WebSocket was standardized as a communication protocol by IETF as RFC 6455 in 2011. Most modern web browsers today support the WebSocket protocol.

WebSocket于2011年被IETF作为RFC 6455标准化为一种通信协议。今天,大多数现代网络浏览器都支持WebSocket协议。

3.2. RESTful HTTP

3.2 RESTful HTTP

While we all are aware of HTTP because of its ubiquitous presence on the internet, it is also an application layer communication protocol. HTTP is a request-response based protocol, again we’ll understand this better later in the tutorial.

虽然我们都知道HTTP,因为它在互联网上无处不在,但它也是一个应用层通信协议。HTTP是一个基于请求-响应的协议,同样我们将在本教程的后面更好地理解这一点。

REST (Representational State Transfer) is an architectural style which puts a set of constraints on HTTP to create web services.

REST(Representational State Transfer)是一种架构风格,它在HTTP上设置了一系列约束条件,以创建网络服务。

4. WebSocket Subprotocol

4.WebSocket子协议

While WebSocket defines a protocol for bi-directional communication between client and server, it does not put any condition on the message to be exchanged. This is left open for parties in the communication to agree as part of subprotocol negotiation.

虽然WebSocket定义了客户端和服务器之间的双向通信协议,但它并没有对要交换的消息提出任何条件。这一点留待通信中的各方作为子协议协商的一部分来达成一致。

It’s not convenient to develop a subprotocol for non-trivial applications. Fortunately, there are many popular subprotocols like STOMP available for use. STOMP stands for Simple Text Oriented Messaging Protocol and works over WebSocket. Spring Boot has first class support for STOMP, which we’ll make use of in our tutorial.

为非琐碎的应用开发一个子协议并不方便。幸运的是,有许多流行的子协议,如STOMP可供使用。STOMP是Simple Text Oriented Messaging Protocol的缩写,通过WebSocket工作。Spring Boot对STOMP有一流的支持,我们将在教程中利用它。

5. Quick Setup in Spring Boot

5.在Spring Boot中的快速设置

There’s nothing better than seeing a working example. So, we’ll build simple use-cases in both WebSocket and RESTful HTTP to explore them further and then compare them. Let’s create a simple server and client component for both.

没有什么比看到一个工作实例更好了。因此,我们将在WebSocket和RESTful HTTP中建立简单的用例,进一步探索它们,然后进行比较。让我们为两者创建一个简单的服务器和客户端组件。

We’ll create a simple client using JavaScript which will send a name. And, we’ll create a server using Java which will respond with a greeting.

我们将使用JavaScript创建一个简单的客户端,它将发送一个名字。然后,我们将用Java创建一个服务器,它将以问候语作为回应。

5.1. WebSocket

5.1 WebSocket

To use WebSocket in Spring Boot, we’ll need the appropriate starter:

要在Spring Boot中使用WebSocket,我们需要适当的启动器

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

We’ll now configure the STOMP endpoints:

我们现在要配置STOMP的端点。

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
 
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws");
    }
 
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.setApplicationDestinationPrefixes("/app");
        config.enableSimpleBroker("/topic");
    }
}

Let’s quickly define a simple WebSocket server which accepts a name and responds with a greeting:

让我们快速定义一个简单的WebSocket服务器,它接受一个名字,并以问候语作出回应。

@Controller
public class WebSocketController {
 
    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(Message message) throws Exception {
        return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
    }
}

Finally, let’s build the client to communicate with this WebSocket server. As we are emphasizing browser-to-server communication, let’s create a client in JavaScript:

最后,让我们建立客户端,与该WebSocket服务器进行通信。由于我们强调的是浏览器与服务器之间的通信,让我们用JavaScript创建一个客户端。

var stompClient = null;
function connect() {
    stompClient = Stomp.client('ws://localhost:8080/ws');
    stompClient.connect({}, function (frame) {
        stompClient.subscribe('/topic/greetings', function (response) {
            showGreeting(JSON.parse(response.body).content);
        });
    });
}
function sendName() {
	stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}
function showGreeting(message) {
    $("#greetings").append("<tr><td>" + message + "</td></tr>");
}

This completes our working example of a WebSocket server and client. There is an HTML page in the code repository which provides a simple user interface to interact with.

这就完成了我们的WebSocket服务器和客户端的工作实例。在代码库中有一个HTML页面,它提供了一个简单的用户界面来进行交互。

While this just scratches the surface, WebSocket with Spring can be used to build complex chat clients and more.

虽然这只是表面现象,但WebSocket与Spring可用于构建复杂的聊天客户端等。

5.2. RESTful HTTP

5.2 RESTful HTTP

We’ll go through a similar set-up for RESTful service now. Our simple web service will accept a GET request with a name and responds with a greeting.

我们现在将对RESTful服务进行类似的设置。我们的简单网络服务将接受一个带有名字的GET请求,并以问候语进行回应。

Let’s use Spring Boot’s web starter instead this time:

这次让我们使用Spring Boot的网络启动器来代替。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Now, we’ll define a REST endpoint leveraging powerful annotation support available in Spring:

现在,我们将利用Spring中强大的注释支持来定义一个REST端点。

@RestController
@RequestMapping(path = "/rest")
public class RestAPIController {
    @GetMapping(path="/{name}", produces = "application/json")
    public String getGreeting(@PathVariable("name") String name)
    {
        return "{\"greeting\" : \"Hello, " + name + "!\"}";
    }
}

Finally, let’s create a client in JavaScript:

最后,让我们在JavaScript中创建一个客户端。

var request = new XMLHttpRequest()
function sendName() {
    request.open('GET', 'http://localhost:8080/rest/'+$("#name").val(), true)
    request.onload = function () {
    	var data = JSON.parse(this.response)
    	showGreeting(data.greeting)
    }
    request.send()
}

function showGreeting(message) {
    $("#greetings").append("<tr><td>" + message + "</td></tr>");
}

That’s pretty much it! Again, there’s an HTML page in code repository to work with a user interface.

基本上就是这样了!同样,在代码库中也有一个HTML页面,可以和用户界面一起工作。

Although profound in its simplicity, defining production grade REST API can be much more extensive task!

虽然它的简单性很高,但定义生产级的REST API可能是更广泛的任务。

6. Comparison of WebSocket and RESTful HTTP

6.WebSocket和RESTful HTTP的比较

Having created minimal, but working, examples of WebSocket and RESTful HTTP, we’re now ready to understand how do they fare against each other. We’ll examine this against several criteria in the next sub-sections.

在创建了WebSocket和RESTful HTTP的最小但可行的示例之后,我们现在准备了解它们之间的竞争情况。我们将在接下来的小节中根据几个标准进行考察。

It is important to note that while we can directly compare HTTP and WebSocket as they are both application layer protocols, it’s not natural to compare REST against WebSocket. As we saw earlier REST is an architectural style which leverages HTTP for communication.

需要注意的是,虽然我们可以直接比较HTTP和WebSocket,因为它们都是应用层协议,但将REST与WebSocket进行比较是不自然的。正如我们之前看到的,REST是一种架构风格,它利用HTTP进行通信。

Hence our comparison to WebSocket will mostly be regarding the capabilities, or lack thereof, in HTTP.

因此,我们与WebSocket的比较主要是关于HTTP的能力或缺乏能力

6.1. URL Scheme

6.1.URL计划

A URL defines the unique location of a web resource and mechanism to retrieve it. In a client-server communication, more often than not we’re looking to get static or dynamic resources through their associated URL.

一个URL定义了网络资源的唯一位置和检索机制。在客户-服务器通信中,更多时候我们希望通过其相关的URL获得静态或动态资源。

We’re all familiar with the HTTP URL scheme:

我们都熟悉HTTP的URL方案。

http://localhost:8080/rest

WebSocket URL scheme is not much different either:

WebSocket的URL方案也没有什么不同。

ws://localhost:8080/ws

At the outset, the only difference seems to be the characters before the colon, but it abstracts a lot which happens under the hood. Let’s explore further.

一开始,唯一的区别似乎是冒号前的字符,但它抽象出了很多发生在引擎盖下的东西。让我们进一步探讨。

6.2. Handshake

6.2 握手

Handshake refers to the automatic way of negotiating communication protocol between communicating parties. HTTP is a stateless protocol and works in a request-response mechanism. On every HTTP request, a TCP connection is established with the server over the socket.

握手 指的是通信各方之间协商通信协议的自动方式。HTTP是一个无状态的协议,以请求-回应的机制工作。在每个HTTP请求中,都会通过套接字与服务器建立一个TCP连接。

The client then waits until the server responds with the resource or an error. The next request from the client repeats everything as if the previous request never happened:

然后客户端等待,直到服务器响应资源或出现错误。客户端的下一个请求会重复一切,就像之前的请求从未发生过一样。

HTTP Connection

WebSocket works very differently compared to HTTP and starts with a handshake before actual communication.

与HTTP相比,WebSocket的工作方式非常不同,在实际通信之前先进行握手。

Let’s see what comprise a WebSocket handshake:

让我们看看WebSocket握手的组成。

WebSocket Connection

In case of WebSocket, the client initiates a Protocol Handshake request in HTTP and then waits until the server responds accepting an upgrade to WebSocket from HTTP.

在WebSocket的情况下,客户端在HTTP中发起协议握手请求,然后等待服务器的回应,接受从HTTP升级到WebSocket

Of course, since Protocol Handshake happens over HTTP, it follows the sequence from the previous diagram. But once the connection is established, from there on client and server switches over to WebSocket for further communication.

当然,由于协议握手是在HTTP上进行的,因此它遵循了上图的顺序。但一旦建立了连接,客户和服务器就会切换到WebSocket进行进一步通信。

6.3. Connection

6.3.连接

As we saw in the previous subsection, one stark difference between WebSocket and HTTP is that WebSocket works on a persistent TCP connection while HTTP creates a new TCP connection for every request.

正如我们在上一小节中看到的,WebSocket和HTTP之间的一个明显区别是,WebSocket在一个持久的TCP连接上工作,而HTTP为每个请求创建一个新的TCP连接。

Now obviously creating new TCP connection for every request is not very performant and HTTP has not been unaware of this. In fact, as part of HTTP/1.1, persistent connections were introduced to alleviate this shortcoming of HTTP.

现在很明显,为每个请求创建新的TCP连接并不是很好的表现,HTTP也不是没有意识到这一点。事实上,作为HTTP/1.1的一部分,持久连接被引入以缓解HTTP的这个缺点。

Nevertheless, WebSocket has been designed from the ground up to work with persistent TCP connections.

尽管如此,WebSocket从一开始就被设计为与持久的TCP连接一起工作

6.4. Communication

6.4.通讯

The benefit of WebSocket over HTTP is a specific scenario that arises from the fact that the client can server can communicate in ways which were not possible with good old HTTP.

WebSocket相对于HTTP的好处是一个特定的场景,它产生于这样一个事实,即客户端和服务器可以用老式HTTP无法实现的方式进行通信。

For instance, in HTTP, usually the client sends that request, and then the server responds with requested data. There is no generic way for the server to communicate with the client on its own. Of course, patterns and solutions have been devised to circumvent this like Server-Sent Events (SSE), but these were not completely natural.

例如,在HTTP中,通常由客户发送该请求,然后由服务器响应所请求的数据。没有通用的方法让服务器自己与客户端进行通信。当然,人们已经设计了一些模式和解决方案来规避这一点,如服务器发送事件(SSE),但这些都不是完全自然的。

With WebSocket, working over persistent TCP communication, it’s possible for server and client both to send data independent of each other, and in fact, to many communicating parties! This is referred to as bi-directional communication.

通过WebSocket,在持久的TCP通信上工作,服务器和客户端都有可能相互独立地发送数据,而且事实上,可以向许多通信方发送数据!这被称为双向通信。这被称为双向通信。

Another interesting feature of WebSocket communication is that it’s full-duplex. Now while this term may sound esoteric; it simply means that both server and client can send data simultaneously. Compare this with what happens in HTTP where the server has to wait until it receives the request in full before it can respond with data.

WebSocket通信的另一个有趣的特点是,它是全双工的。现在,虽然这个术语听起来很深奥,但它只是意味着服务器和客户端可以同时发送数据。与HTTP中的情况相比,在HTTP中,服务器必须等待,直到完全收到请求后才能响应数据。

While the benefit of bi-directional and full-duplex communication may not be apparent immediately. we’ll see some of the use-cases where they unlock some real power.

虽然双向和全双工通信的好处可能不会立即显现出来,但我们将看到它们释放一些真正力量的一些使用情况。

6.5. Security

6.5.安全问题

Last but not least, both HTTP and WebSocket leverage the benefits of TLS for security. While HTTP offers https as part of their URL scheme to use this, WebSocket has wss as part of their URL scheme for the same effect.

最后但并非最不重要的是,HTTP和WebSocket都利用了TLS的优势来保证安全。虽然HTTP将https作为其URL方案的一部分来使用,但WebSocket将wss作为其URL方案的一部分,以达到同样的效果。

So the secured version of URLs from the previous subsection should look like:

因此,上一小节中的安全版本的URLs应该看起来像。

https://localhost:443/rest
wss://localhost:443/ws

Securing either a RESTful service or a WebSocket communication is a subject of much depth and can not be covered here. For now, let’s just say that both are adequately supported in this regard.

确保RESTful服务或WebSocket通信的安全是一个很有深度的话题,在此不作介绍。现在,我们只想说,两者在这方面都得到了充分的支持。

6.6. Performance

6.6.业绩

We must understand that WebSocket is a stateful protocol where communication happens over a dedicated TCP connection. On the other hand, HTTP is inherently a stateless protocol. This has an impact on how these will perform with the load but that really depends on the use case.

我们必须明白,WebSocket是一个有状态的协议,通信通过专用的TCP连接进行。另一方面,HTTP本质上是一个无状态协议。这对这些协议在负载下的表现有影响,但这确实取决于用例。

Since communication over WebSocket happens over a reusable TCP connection, the overhead per message is lower compared to HTTP. Hence it can reach higher throughput per server. But there is a limit to which a single server can scale and that is where WebSocket has issues. It’s not easy to horizontally scale applications with WebSockets.

由于WebSocket的通信是通过可重复使用的TCP连接进行的,因此与HTTP相比,每条消息的开销较低。因此,它可以使每台服务器达到更高的吞吐量。但是,单台服务器的规模是有限的,这就是WebSocket的问题所在。用WebSockets横向扩展应用程序并不容易。

This is where HTTP shines. With HTTP each new request can potentially land on any server. This implies that to increase overall throughput we can easily add more servers. This should potentially have no impact on the application running with HTTP.

这就是HTTP的魅力所在。通过HTTP,每个新的请求都有可能落在任何服务器上。这意味着,为了增加整体吞吐量,我们可以很容易地增加更多的服务器。这对使用HTTP运行的应用程序应该是没有影响的。

Obviously an application may itself need state and session stickiness which can make it easier said than done.

显然,一个应用程序本身可能需要状态和会话粘性,这可能使它说起来容易做起来难。

7. Where Should We Use Them?

7.我们应该在哪里使用它们?

Now, we have seen enough of RESTful service over HTTP and simple communication over WebSocket to form our opinion around them. But where should we use what?

现在,我们已经看到了足够多的通过HTTP的RESTful服务和通过WebSocket的简单通信,并围绕它们形成了我们的观点。但是,我们应该在哪里使用什么?

It’s important to remember that while WebSocket has emerged out of shortcomings in HTTP, it’s not, in fact, a replacement of HTTP. So they both have their place and their uses. Let’s quickly understand how can we make a decision.

重要的是要记住,虽然WebSocket是在HTTP的缺点中出现的,但事实上它并不是HTTP的替代品。因此,它们都有各自的位置和用途。让我们快速了解一下如何才能做出决定。

For the bulk of the scenario where occasional communication is required with the server like getting the record of an employee, it’s still sensible to use REST service over HTTP/S. But for newer client-side applications like a stock-price application which requires real-time updates from the server, it’s much convenient to leverage WebSocket.

对于大多数情况下需要与服务器进行偶尔的通信,如获取员工的记录,使用HTTP/S的REST服务仍然是明智的。但对于较新的客户端应用,如需要从服务器实时更新的股票价格应用,利用WebSocket就方便多了。

Generalizing, WebSocket is more suitable for cases where a push-based and real-time communication defines the requirement more appropriately. Additionally, WebSocket works well for scenarios where a message needs to be pushed to multiple clients simultaneously. These are the cases where client and server communication over RESTful services will find it difficult if not prohibitive.

综上所述,WebSocket更适用于基于推送和实时通信的需求定义的情况下。此外,WebSocket 非常适用于需要同时向多个客户端推送消息的场景。在这些情况下,客户端和服务器通过RESTful服务进行通信将发现困难重重,甚至令人望而却步。

Nevertheless, the use of WebSocket and RESTful services over HTTP needs to be drawn from the requirements. Like there are no silver bullets, we can’t just expect to pick one to solve every problem. Hence, we must use our wisdom coupled with knowledge in designing an efficient communication model.

尽管如此,需要从需求中得出WebSocket和RESTful服务在HTTP上的使用。就像没有银弹一样,我们不能只指望选取一种来解决所有问题。因此,我们必须用我们的智慧加上知识来设计一个高效的通信模型。

8. Conclusion

8.结语

In this tutorial, we reviewed the basics of network communication with an emphasis on application layer protocols HTTP and WebSocket. We saw some quick demonstrations of WebSocket and RESTful API over HTTP in Spring Boot.

在本教程中,我们回顾了网络通信的基础知识,重点是应用层协议HTTP和WebSocket。我们看到了Spring Boot中WebSocket和RESTful API通过HTTP的一些快速演示。

And finally, we compared the features of HTTP and WebSocket protocols and briefly discussed when to use each.

最后,我们比较了HTTP和WebSocket协议的特点,并简要讨论了何时使用这两种协议。

As always, the code for the examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到