我使用 Go 已经有一段时间了,但之前从未使用过 SSE。我遇到了一个问题,有人可以提供一个仅发送给特定用户(连接)的服务器发送事件的工作示例吗?
我正在使用 gorilla - 会话进行身份验证,并且我想使用 UserID 来分隔连接。
或者我应该通过 Ajax 使用 5 秒轮询?
非常感谢
这是我发现并尝试过的:
-
https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c 它不会发送给个人用户,并且如果连接关闭,go func 也不会停止
-
https://github.com/striversity/gotr/blob/master/010-server-sent-event-part-2/main.go 这正是我所需要的,但一旦连接被删除。所以现在,一旦您在私人窗口中关闭并打开浏览器,它就根本无法工作。另外,如上所述,Go 例程继续进行。
正确答案
创建一个“代理”来将消息分发给连接的用户:
type broker struct {
// users is a map where the key is the user id
// and the value is a slice of channels to connections
// for that user id
users map[string][]chan []byte
// actions is a channel of functions to call
// in the broker's goroutine. the broker executes
// everything in that single goroutine to avoid
// data races.
actions chan func()
}
// run executes in a goroutine. it simply gets and
// calls functions.
func (b *broker) run() {
for a := range b.actions {
a()
}
}
func newbroker() *broker {
b := &broker{
users: make(map[string][]chan []byte),
actions: make(chan func()),
}
go b.run()
return b
}
// adduserchan adds a channel for user with given id.
func (b *broker) adduserchan(id string, ch chan []byte) {
b.actions <- func() {
b.users[id] = append(b.users[id], ch)
}
}
// removeuserchan removes a channel for a user with the given id.
func (b *broker) removeuserchan(id string, ch chan []byte) {
// the broker may be trying to send to
// ch, but nothing is receiving. pump ch
// to prevent broker from getting stuck.
go func() { for range ch {} }()
b.actions <- func() {
chs := b.users[id]
i := 0
for _, c := range chs {
if c != ch {
chs[i] = c
i = i + 1
}
}
if i == 0 {
delete(b.users, id)
} else {
b.users[id] = chs[:i]
}
// close channel to break loop at beginning
// of removeuserchan.
// this must be done in broker goroutine
// to ensure that broker does not send to
// closed goroutine.
close(ch)
}
}
// sendtouser sends a message to all channels for the given user id.
func (b *broker) sendtouser(id string, data []byte) {
b.actions <- func() {
for _, ch := range b.users[id] {
ch <- data
}
}
}
在包级别使用代理声明变量:
var broker = newbroker()
使用代理编写 sse 端点:
func sseEndpoint(w http.ResponseWriter, r *http.Request) {
// I assume that user id is in query string for this example,
// You should use your authentication code to get the id.
id := r.FormValue("id")
// Do the usual SSE setup.
flusher := w.(http.Flusher)
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
// Create channel to receive messages for this connection.
// Register that channel with the broker.
// On return from the function, remove the channel
// from the broker.
ch := make(chan []byte)
broker.addUserChan(id, ch)
defer broker.removeUserChan(id, ch)
for {
select {
case <-r.Context().Done():
// User closed the connection. We are out of here.
return
case m := <-ch:
// We got a message. Do the usual SSE stuff.
fmt.Fprintf(w, "data: %s\n\n", m)
flusher.Flush()
}
}
}
向您的应用程序添加代码以调用 broker.sendtouser。
以上就是Golang 服务器向每个用户发送的事件的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756
相关文章
发现更多好内容- 如何使用 Javascript 的 escape()函数和 unescape()函数?(Javascript escape()函数和unescape()函数怎么用)
- 【JavaScript】ES6 中class定义类
- 数据科学岗位将在未来5年内重新洗牌,你准备好转型了吗?
- 如何理解 apisix Java 的错误处理机制?(apisix Java的错误处理机制)
- 自动驾驶仿真测试技术可模拟真实街景
- 沉默还是抵制?84家公司被列入加班黑名单
- 用Select * 进行SQL查询的七宗罪
- 大数据与人工智能,你都分不清楚,居然还要走向人生巅峰
- Java 中定义接口的关键字究竟是什么?(java定义接口的关键字是什么)
- 程序员的宿命是怎样的