文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

构建一个即时消息应用(五):实时消息

2024-12-10 15:33

关注

本文是该系列的第五篇。

对于实时消息,我们将使用 服务器发送事件Server-Sent Events。这是一个打开的连接,我们可以在其中传输数据流。我们会有个端点,用户会在其中订阅发送给他的所有消息。

消息户端

在 HTTP 部分之前,让我们先编写一个映射map ,让所有客户端都监听消息。 像这样全局初始化:

  1. type MessageClient struct { 
  2.     Messages chan Message 
  3.     UserID   string 
  4.  
  5. var messageClients sync.Map 

已创建的新消息

还记得在 上一篇文章 中,当我们创建这条消息时,我们留下了一个 “TODO” 注释。在那里,我们将使用这个函数来调度一个 goroutine。

  1. go messageCreated(message) 

把这行代码插入到我们留注释的位置。

  1. func messageCreated(message Message) error { 
  2.     if err := db.QueryRow(` 
  3.         SELECT user_id FROM participants 
  4.         WHERE user_id != $1 and conversation_id = $2 
  5.     `, message.UserID, message.ConversationID). 
  6.     Scan(&message.ReceiverID); err != nil { 
  7.         return err 
  8.     } 
  9.  
  10.     go broadcastMessage(message) 
  11.  
  12.     return nil 
  13.  
  14. func broadcastMessage(message Message) { 
  15.     messageClients.Range(func(key, _ interface{}) bool { 
  16.         client := key.(*MessageClient) 
  17.         if client.UserID == message.ReceiverID { 
  18.             client.Messages <- message 
  19.         } 
  20.         return true 
  21.     }) 

该函数查询接收者 ID(其他参与者 ID),并将消息发送给所有客户端。

订阅消息

让我们转到 main() 函数并添加以下路由:

  1. router.HandleFunc("GET""/api/messages", guard(subscribeToMessages)) 

此端点处理 /api/messages 上的 GET 请求。请求应该是一个 EventSource 连接。它用一个事件流响应,其中的数据是 JSON 格式的。

  1. func subscribeToMessages(w http.ResponseWriter, r *http.Request) { 
  2.     if a := r.Header.Get("Accept"); !strings.Contains(a, "text/event-stream") { 
  3.         http.Error(w, "This endpoint requires an EventSource connection", http.StatusNotAcceptable) 
  4.         return 
  5.     } 
  6.  
  7.     f, ok := w.(http.Flusher) 
  8.     if !ok { 
  9.         respondError(w, errors.New("streaming unsupported")) 
  10.         return 
  11.     } 
  12.  
  13.     ctx := r.Context() 
  14.     authUserID := ctx.Value(keyAuthUserID).(string) 
  15.  
  16.     h := w.Header() 
  17.     h.Set("Cache-Control""no-cache"
  18.     h.Set("Connection""keep-alive"
  19.     h.Set("Content-Type""text/event-stream"
  20.  
  21.     messages := make(chan Message) 
  22.     defer close(messages) 
  23.  
  24.     client := &MessageClient{Messages: messages, UserID: authUserID} 
  25.     messageClients.Store(client, nil) 
  26.     defer messageClients.Delete(client) 
  27.  
  28.     for { 
  29.         select { 
  30.         case <-ctx.Done(): 
  31.             return 
  32.         case message := <-messages: 
  33.             if b, err := json.Marshal(message); err != nil { 
  34.                 log.Printf("could not marshall message: %v\n", err) 
  35.                 fmt.Fprintf(w, "event: error\ndata: %v\n\n", err) 
  36.             } else { 
  37.                 fmt.Fprintf(w, "data: %s\n\n", b) 
  38.             } 
  39.             f.Flush() 
  40.         } 
  41.     } 

首先,它检查请求头是否正确,并检查服务器是否支持流式传输。我们创建一个消息通道,用它来构建一个客户端,并将其存储在客户端映射中。每当创建新消息时,它都会进入这个通道,因此我们可以通过 for-select 循环从中读取。

服务器发送事件Server-Sent Events使用以下格式发送数据:

  1. data: some data here\n\n 

我们以 JSON 格式发送:

  1. data: {"foo":"bar"}\n\n 

我们使用 fmt.Fprintf() 以这种格式写入响应写入器writter,并在循环的每次迭代中刷新数据。

这个循环会一直运行,直到使用请求上下文关闭连接为止。我们延迟了通道的关闭和客户端的删除,因此,当循环结束时,通道将被关闭,客户端不会收到更多的消息。

注意,服务器发送事件Server-Sent Events(EventSource)的 JavaScript API 不支持设置自定义请求头😒,所以我们不能设置 Authorization: Bearer 。这就是为什么 guard() 中间件也会从 URL 查询字符串中读取令牌的原因。


实时消息部分到此结束。我想说的是,这就是后端的全部内容。但是为了编写前端代码,我将再增加一个登录端点:一个仅用于开发的登录。

 

 

来源:Linux中国内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯