如何在连接丢失时停止golang的处理程序函数

huangapple go评论85阅读模式
英文:

How golang stop handler function if connection is lost

问题

似乎即使连接丢失,处理程序函数仍然在运行。例如,如果我访问http://0.0.0.0:8000/home并突然关闭浏览器,屏幕将继续打印所有的数字。

package main

import (
	"fmt"
	"net/http"
	"time"
)

func main() {
	http.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) {
		i := 0
		for {
			fmt.Println("i", i)
			i++
			time.Sleep(time.Microsecond * 15)
		}
	})
	http.ListenAndServe(":8000", nil)
}

相关链接:https://stackoverflow.com/questions/53323110/how-golang-gin-stop-handler-function-immediately-if-connection-is-lost

英文:

It seems even if the connection is lost, the handler function is still running. For example, if I visit http://0.0.0.0:8000/home and close the browser suddenly, the screen will continue to print all the numbers.

package main

import (
	"fmt"
	"net/http"
	"time"
)

func main() {
	http.HandleFunc("/home", func(w http.ResponseWriter, r *http.Request) {
		i := 0
		for {
			fmt.Println("i", i)
			i++
			time.Sleep(time.Microsecond * 15)
		}
	})
	http.ListenAndServe(":8000", nil)
}

related: https://stackoverflow.com/questions/53323110/how-golang-gin-stop-handler-function-immediately-if-connection-is-lost

答案1

得分: 2

选项1:在断开连接时,使用断开连接的连接写入会返回错误。当fmt.Println返回错误时,退出循环。

func example(w http.ResponseWriter, r *http.Request) {
    i := 0
    for {
        _, err := fmt.Println("i", i)
        if err != nil {
            return
        }
        i++
        time.Sleep(time.Microsecond * 15)
    }
}

选项2:服务器在断开连接时取消请求上下文。只要上下文未被取消,就循环执行。

func example(w http.ResponseWriter, r *http.Request) {
    i := 0
    c := r.Context()
    for c.Err() == nil {
        fmt.Println("i", i)
        i++
        time.Sleep(time.Microsecond * 15)
    }
}

选项3:服务器在断开连接时取消请求上下文。循环等待上下文取消或计时器。在取消时退出。

func example(w http.ResponseWriter, r *http.Request) {
    t := time.NewTicker(time.Microsecond * 15)
    defer t.Stop()
    done := r.Context().Done()
    for {
        select {
        case <-done:
            fmt.Println("Done!")
            return
        case t := <-t.C:
            fmt.Println("Current time:", t)
        }
    }
}

选项3会更早地返回处理程序。选项1和2在处理程序返回之前始终等待sleep完成。

英文:

Option 1: Write on a disconnected connection returns an error. Break from the loop when fmt.Println returns an error.

func example(w http.ResponseWriter, r *http.Request) {
	i := 0
	for {
		_, err := fmt.Println(&quot;i&quot;, i)
		if err != nil {
			return
		}
		i++
		time.Sleep(time.Microsecond * 15)
	}
}

Option 2: The server cancels the request context on disconnect. Loop while the context is not canceled.

func example(w http.ResponseWriter, r *http.Request) {
	i := 0
	c := r.Context()
	for c.Err() == nil {
		fmt.Println(&quot;i&quot;, i)
		i++
		time.Sleep(time.Microsecond * 15)
	}
}

Option 3: The server cancels the request context on disconnect. Loop waiting for context cancelation or timer. Exit on cancelation.

func example(w http.ResponseWriter, r *http.Request) {
	t := time.NewTicker(time.Microsecond * 15)
	defer t.Stop()
	done := r.Context().Done()
	for {
		for {
			select {
			case &lt;-done:
				fmt.Println(&quot;Done!&quot;)
				return
			case t := &lt;-t.C:
				fmt.Println(&quot;Current time: &quot;, t)
			}
		}
	}
}

The handler will return earlier with option 3.
Option 1 and 2 always wait for sleep to complete before handler returns.

huangapple
  • 本文由 发表于 2023年1月17日 02:58:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/75138579.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定