让我们假设客户端通过http上较慢的Internet连接上传沉重的图像,他打开与服务器的连接,开始写入数据,由于网络问题突然失去了该连接。如果尚未调用处理程序函数,如何在服务器上检测到此错误。我找到的解决方案是检查连接状态。但问题在于它不可扩展,因为许多goroutine将与全局变量交互。还有更优雅的解决方案吗?
package main
import (
"fmt"
"log"
"net"
"net/http"
)
// current state of connections
var connStates = make(map[string]http.ConnState)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("got new request")
fmt.Println(connStates)
})
srv := &http.Server{
Addr: ":8080",
ConnState: func(conn net.Conn, event http.ConnState) {
if event != http.StateClosed {
connStates[conn.RemoteAddr().String()] = event
} else {
if connStates[conn.RemoteAddr().String()] == http.StateActive {
fmt.Println("client cancelled request")
}
delete(connStates, conn.RemoteAddr().String())
}
},
}
log.Fatal(srv.ListenAndServe())
}
答案 0 :(得分:1)
例如,您可以在处理程序中使用context,这将检测客户端何时断开连接并返回,并且http.StatusPartialContent
除了在可能具有日志记录逻辑的位置调用someCleanup()
之外。
https://play.golang.org/p/5Yr_HBuyiZW
func helloWorld(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ch := make(chan struct{})
go func() {
time.Sleep(5 * time.Second)
fmt.Fprintln(w, "Hello World!")
ch <- struct{}{}
}()
select {
case <-ch:
case <-ctx.Done():
http.Error(w, ctx.Err().Error(), http.StatusPartialContent)
someCleanUP()
}
}
答案 1 :(得分:0)
如果只需要日志,甚至可以简化代码:
srv := &http.Server{
Addr: ":8080",
ConnState: func(conn net.Conn, event http.ConnState) {
log.Printf("addr: %s, changed state to: %s", conn.RemoteAddr(), event.String())
},
}
每次conn
更改都会触发该回调