在Go中检测失败的HTTP连接

时间:2019-04-27 19:19:24

标签: http go

让我们假设客户端通过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())
}

2 个答案:

答案 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更改都会触发该回调