在现代 web 应用中,实时数据更新已经成为了不可或缺的功能。很多人可能会认为实现这个功能需要使用 WebSockets 或长轮询(long polling)等技术,但其实还有一种更简单、更高效的方法:Server-sent Events。
本文将详细介绍 Server-sent Events 技术,并且教你如何在 Angular 应用中利用它进行实时数据更新。
什么是 Server-sent Events?
Server-sent Events,也就是服务器推送事件,是一种基于 HTTP 的实时通信技术。它的基本原理是客户端通过 HTTP 连接到服务器,服务器保持连接打开,并随时向客户端发送消息。
Server-sent Events 与 WebSockets 的最大区别是:前者是基于 HTTP 协议建立的长连接,而后者则是基于 TCP 协议建立的长连接。因此 Server-sent Events 相对于 WebSockets 来说更适合那些只需要单向数据传输,而且希望减少网络负载的应用场景。
如何在 Angular 应用中利用 Server-sent Events 进行实时数据更新?
要使用 Server-sent Events 技术,我们首先需要了解它的 API。
Server-sent Events 的 API
在 JavaScript 中使用 Server-sent Events,可以通过以下的两个 API 进行:
// javascriptcn.com 代码示例 const eventSource = new EventSource(url); eventSource.onmessage = function(event) { // 处理服务器发送的数据 } eventSource.onerror = function(event) { // 处理错误 }
其中,EventSource
构造函数需要传递一个 URL,该 URL 指向服务器响应 SSE 的端点。一旦连接建立成功,服务器就可以随时向客户端发送数据了。
如果服务器向客户端发送了数据,onmessage
回调函数就会被触发。我们可以在该函数中进行数据的处理。如果连接出现错误,onerror
回调函数就会被触发,我们也可以在该函数中处理这个错误。
以上是 Server-sent Events 的核心 API。下面,我们将使用 Angular 来实现一个具有实时数据更新功能的示例应用。
在 Angular 中使用 Server-sent Events
假设我们正在开发一个在线聊天应用,当其他用户发送消息时,我们希望这个应用能够实时地接收到最新的消息。
首先,我们需要在服务器端设置 SSE 的端点,并为客户端提供一个唯一的标识符(比如说用户名)。当其他用户发送消息时,服务器会将消息发送给所有正在监听该标识符的客户端。
在我们的 Angular 应用中,我们需要创建一个 ChatService
,该服务将负责监听 SSE 端点,并把收到的消息广播给所有需要它的组件。
以下是 ChatService
的核心代码:
// javascriptcn.com 代码示例 @Injectable({ providedIn: 'root' }) export class ChatService { private eventSource: EventSource; private messageSubject: Subject<string> = new Subject<string>(); private readonly SSE_ENDPOINT_URL = '/api/sse/chat-messages?username='; constructor(private http: HttpClient, private authService: AuthService) { } public listenForMessages(): Observable<string> { if(!this.eventSource) { const username = this.authService.getCurrentUser().username; const url = this.SSE_ENDPOINT_URL + username; this.eventSource = new EventSource(url); this.eventSource.onmessage = event => { this.messageSubject.next(event.data); } this.eventSource.onerror = event => { console.error(event); } } return this.messageSubject.asObservable(); } }
ChatService
中有一个 listenForMessages()
方法。当我们调用该方法时,它会检查是否已经建立了 SSE 连接。如果没有,它会创建一个新的连接。一旦有数据到达,它就会广播给所有需要它的组件。
以下是一个使用 ChatService
的组件:
// javascriptcn.com 代码示例 export class ChatComponent implements OnInit, OnDestroy { public messages: string[] = []; constructor(private chatService: ChatService) { } ngOnInit(): void { this.chatService.listenForMessages().subscribe(message => { this.messages.push(message); }); } ngOnDestroy(): void { // 记得在组件销毁时关闭 SSE 连接。 this.chatService.closeConnection(); } }
在该组件中,我们订阅了 ChatService
中的数据源,并将接收到的消息添加到 messages
数组中。
服务器端代码
在服务器端,我们需要编写一个 RESTful API,它能够将接收到的消息发送给所有正在监听该标识符的客户端。以下是一个使用 Node.js + Express 实现的 SSE 消息推送端点的示例:
// javascriptcn.com 代码示例 app.get('/api/sse/chat-messages', function(req, res) { const username = req.query.username; const clients = new Set(); res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.flushHeaders(); req.on('close', function() { clients.delete(res); }); setInterval(function() { const message = generateRandomMessage(); for (const client of clients) { client.write(`data: ${username}: ${message}\n\n`); } }, 3000); clients.add(res); });
以上代码中,我们创建了一个 /api/sse/chat-messages
端点,它接收一个 username
参数,并使用该参数来标识客户端。每隔 3 秒钟,服务器会向正在连接到该端点的所有客户端发送一条随机的聊天消息。
当客户端连接到 SSE 端点时,我们将其 response
对象加入到一个 Set
中,并设置一些 HTTP 头部以便与客户端保持连接。当客户端关闭连接时,我们会将它从 Set
中删除。注意,我们并没有直接在该端点中发送实际的聊天消息。相反,我们在另一个独立于端点的函数中发送了消息,并通过 Set
来保存所有客户端的 response
对象。当有新消息到达时,我们遍历当前所有客户端的 response
对象,并向它们发送该消息。
总结
在本文中,我们介绍了使用 Server-sent Events 技术来进行实时数据更新的方法,并演示了如何在 Angular 应用中使用它。相较于 WebSockets 等技术,使用 SSE 既简单又高效,并且可以有效地减少网络负载。希望本文对您有所帮助,谢谢!
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6528f8a27d4982a6ebb892de