英文:
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)
}
答案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("i", 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("i", 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 <-done:
				fmt.Println("Done!")
				return
			case t := <-t.C:
				fmt.Println("Current time: ", t)
			}
		}
	}
}
The handler will return earlier with option 3.
Option 1 and 2 always wait for sleep to complete before handler returns.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论