为了账号安全,请及时绑定邮箱和手机立即绑定

HTTP 服务器 HandleFunc 超时循环?

HTTP 服务器 HandleFunc 超时循环?

Go
不负相思意 2023-07-31 17:23:04
我正在开发一个带有网络服务器的 Go 应用程序。我试图添加超时并遇到问题。这是我用来重现它的示例代码,因为发布实际代码是不可能的:package mainimport (    "fmt"    "html/template"    "net/http"    "time")var layout *template.Templatefunc 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 次,并且浏览器显示连接重置错误。我期望超时后,函数将立即结束,连接关闭,浏览器停止加载并显示错误。我怎样才能实现这个目标?
查看完整描述

1 回答

?
杨__羊羊

TA贡献1943条经验 获得超7个赞

立即响应使用 goroutine 和上下文超时


package main


import (

    "context"

    "fmt"

    "html/template"

    "net/http"

    "time"

)


var layout *template.Template

var WriteTimeout = 1 * time.Second


func main() {

    router := http.NewServeMux()

    server := &http.Server{

        Addr:         ":8889",

        Handler:      router,

        ReadTimeout:  5 * time.Second,

        WriteTimeout: WriteTimeout + 10*time.Millisecond, //10ms Redundant time

        IdleTimeout:  15 * time.Second,

    }

    router.HandleFunc("/", home)

    server.ListenAndServe()

}


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

    fmt.Printf("responding\n")

    ctx, _ := context.WithTimeout(context.Background(), WriteTimeout)

    worker, cancel := context.WithCancel(context.Background())

    var buffer string

    go func() {

        // do something

        time.Sleep(2 * time.Second)

        buffer = "ready all response\n"

        //do another

        time.Sleep(2 * time.Second)

        cancel()

        fmt.Printf("worker finish\n")

    }()

    select {

    case <-ctx.Done():

        //add more friendly tips

        w.WriteHeader(http.StatusInternalServerError)

        return

    case <-worker.Done():

        w.Write([]byte(buffer))

        fmt.Printf("writed\n")

        return

    }

}


查看完整回答
反对 回复 2023-07-31
  • 1 回答
  • 0 关注
  • 126 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信