golang web server如何知道client是否已经断开
背景
在web http服务中有些时候如果请求的服务端运行时间比较长,而在其中客户端放弃了请求,那么此时服务端可以迅速放弃正在进行的操作,因为也不能把结果返回给客户端了,否则也是浪费资源,甚至产生副作用。
如何解决这个问题
golang的Context可以用来处理这种场景。
详细请参考Context的文档:https://blog.golang.org/context
举例
服务端代码:
package main
import (
"fmt"
"log"
"time"
"net/http"
"github.com/gorilla/mux"
)
func main() {
address := fmt.Sprintf("%s:%d", "0.0.0.0", 8080)
router := mux.NewRouter().StrictSlash(true)
router.HandleFunc("/test", testHandle)
err := http.ListenAndServe(address, router)
if err != nil {
log.Panic("ListenAndServe err:", err)
}
}
func testHandle(w http.ResponseWriter, r *http.Request) {
log.Printf("Client request is coming\n");
ctx := r.Context()
time.Sleep(10 * time.Second)
select {
case <-ctx.Done():
log.Printf("\tClient has broken\n");
break
default:
log.Printf("\tSend client response\n");
w.Write([]byte("I am OK"))
}
}
这个服务器提供一个localhost:8080/test的URL请求服务,这个服务需要10秒,然后返回"I am OK"给client端,因为在10秒时间间隔内,客户端可能放弃请求,那么server能感应到客户端是否已经放弃了请求。
客户端调用:
- case 1: 正常未放弃
客户端输出:
$ time curl localhost:8080/test
I am OK
real 0m10.012s
user 0m0.003s
sys 0m0.004s
server段输出:
$ go build && ./test
2019/05/20 03:22:51 Client request is coming
2019/05/20 03:23:01 Send client response
- case 2: client端中途放弃
client端输出:
$ time curl --max-time 5 localhost:8080/test
curl: (28) Operation timed out after 5000 milliseconds with 0 out of -1 bytes received
real 0m5.006s
user 0m0.001s
sys 0m0.005s
server端输出:
$ go build && ./test
2019/05/20 03:24:45 Client request is coming
2019/05/20 03:24:55 Client has broken
- case 3:通过浏览器测试
可以通过关闭浏览器页面的方式来模拟client放弃操作。可以达到同样的server端效果。