【发布时间】:2019-11-13 01:07:30
【问题描述】:
我正在使用 HTTP 和 Websockets 构建一个单页应用程序。用户提交表单,我将响应流式传输到客户端。下面是一个 sn-p 客户端。
var html = `<!DOCTYPE html>
<meta charset="utf-8">
<head>
</head>
<body>
<script>
var ws = new WebSocket("ws://localhost:8000/ws")
ws.onmessage = function(e) {
document.getElementById("output").innerHTML += e.data + "<br>"
}
function submitFunction() {
document.getElementById("output").innerHTML += ""
return false
}
</script>
<form
enctype="multipart/x-www-form-urlencoded"
action="http://localhost:8000/"
method="post"
>`
这是服务器。如果请求不是 POST,我编写/呈现建立新 websocket 连接的 html (parseAndExecute)。如果请求是 POST(来自表单),那么我开始处理并最终写入 websocket。
func (c *Config) ServeHtml(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
//process
channel <- data
}
c.parseAndExecute(w)
}
func (sh *SocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.Write([]byte(fmt.Sprintf("", err)))
return
}
//defer ws.Close()
// discard received messages
go func(c *websocket.Conn) {
for {
if _, _, err := c.NextReader(); err != nil {
c.Close()
break
}
}
}(ws)
data <- channel
只有当我不刷新页面时,一切都会按我的预期工作。如果我不刷新,我可以继续提交表单,然后逐行查看不同的输出。澄清一下,它实际上只有在页面已经启动时才有效,因此永远不会调用 parseAndExecute。该函数解析并执行 html/template 创建一个新的 websocket 客户端。
任何刷新页面或最初浏览 localhost:8000 都会导致服务器上出现websocket: close sent。
我不确定如何解决这个问题。服务器是否需要优雅地处理断开连接并允许重新连接?还是客户需要做点什么?似乎服务器应该升级/ws 的任何连接,所以创建多少新的 websocket 客户端并不重要,但显然我的理解是错误的。
我没有关闭服务器上的 websocket 连接,因为只要程序正在运行,它就应该一直在运行。当用户停止程序时,我认为它会自动关闭。
完整的 SocketHandler 代码:
func (sh *SocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.Write([]byte(fmt.Sprintf("", err)))
return
}
// discard received messages
go func(c *websocket.Conn) {
for {
if _, _, err := c.NextReader(); err != nil {
c.Close()
break
}
}
}(ws)
cmd := <-sh.cmdCh
log.Printf("Executing")
stdout, err := cmd.StdoutPipe()
if err != nil {
w.Write([]byte(err.Error()))
return
}
defer stdout.Close()
stderr, err := cmd.StderrPipe()
if err != nil {
w.Write([]byte(err.Error()))
return
}
defer stderr.Close()
if err := cmd.Start(); err != nil {
w.Write([]byte(err.Error()))
return
}
s := bufio.NewScanner(io.MultiReader(stdout, stderr))
for s.Scan() {
err := ws.WriteMessage(1, s.Bytes())
if err != nil {
log.Printf("Error writing to client: %v", err)
ws.Close()
}
}
if err := cmd.Wait(); err != nil {
w.Write([]byte(err.Error()))
return
}
log.Println("Done")
}
【问题讨论】:
标签: javascript html go