猿问

HTTP 服务器 HandleFunc 超时循环?

我正在开发一个带有网络服务器的 Go 应用程序。我试图添加超时并遇到问题。这是我用来重现它的示例代码,因为发布实际代码是不可能的:


package main


import (

    "fmt"

    "html/template"

    "net/http"

    "time"

)


var layout *template.Template


func main() {

    router := http.NewServeMux()

    server := &http.Server{

        Addr:         ":8888",

        Handler:      router,

        ReadTimeout:  5 * time.Second,

        WriteTimeout: 1 * time.Second,

        IdleTimeout:  15 * time.Second,

    }


    router.HandleFunc("/", home)


    var err error

    layout, err = template.ParseFiles("./layout.html")

    if err != nil {

        fmt.Printf("Error1: %+v\n", err)

    }


    server.ListenAndServe()

}


func home(w http.ResponseWriter, r *http.Request) {

    fmt.Println("responding")

    err := layout.Execute(w, template.HTML(`World`))

    if err != nil {

        fmt.Printf("Error2: %+v\n", err)

    }

    time.Sleep(5 * time.Second)

}

布局.html: Hello {{.}}!


当我运行它并访问 127.0.0.1:8888 时,浏览器保持加载状态,并且触发超时home(),重新开始,它在停止之前执行了 10 次,并且浏览器显示连接重置错误。


我期望超时后,函数将立即结束,连接关闭,浏览器停止加载并显示错误。


我怎样才能实现这个目标?


不负相思意
浏览 127回答 1
1回答

杨__羊羊

立即响应使用 goroutine 和上下文超时package mainimport (&nbsp; &nbsp; "context"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "html/template"&nbsp; &nbsp; "net/http"&nbsp; &nbsp; "time")var layout *template.Templatevar WriteTimeout = 1 * time.Secondfunc main() {&nbsp; &nbsp; router := http.NewServeMux()&nbsp; &nbsp; server := &http.Server{&nbsp; &nbsp; &nbsp; &nbsp; Addr:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;":8889",&nbsp; &nbsp; &nbsp; &nbsp; Handler:&nbsp; &nbsp; &nbsp; router,&nbsp; &nbsp; &nbsp; &nbsp; ReadTimeout:&nbsp; 5 * time.Second,&nbsp; &nbsp; &nbsp; &nbsp; WriteTimeout: WriteTimeout + 10*time.Millisecond, //10ms Redundant time&nbsp; &nbsp; &nbsp; &nbsp; IdleTimeout:&nbsp; 15 * time.Second,&nbsp; &nbsp; }&nbsp; &nbsp; router.HandleFunc("/", home)&nbsp; &nbsp; server.ListenAndServe()}func home(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; fmt.Printf("responding\n")&nbsp; &nbsp; ctx, _ := context.WithTimeout(context.Background(), WriteTimeout)&nbsp; &nbsp; worker, cancel := context.WithCancel(context.Background())&nbsp; &nbsp; var buffer string&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; // do something&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(2 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; buffer = "ready all response\n"&nbsp; &nbsp; &nbsp; &nbsp; //do another&nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(2 * time.Second)&nbsp; &nbsp; &nbsp; &nbsp; cancel()&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("worker finish\n")&nbsp; &nbsp; }()&nbsp; &nbsp; select {&nbsp; &nbsp; case <-ctx.Done():&nbsp; &nbsp; &nbsp; &nbsp; //add more friendly tips&nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(http.StatusInternalServerError)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; case <-worker.Done():&nbsp; &nbsp; &nbsp; &nbsp; w.Write([]byte(buffer))&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("writed\n")&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答