HTTP服务器HandleFunc循环超时?

HTTP服务器HandleFunc循环超时?,http,go,server,timeout,Http,Go,Server,Timeout,我正在开发一个具有web服务器的Go应用程序。我试图添加超时,但遇到了一个问题。下面是我为复制它而制作的示例代码,因为发布实际代码是不可能的: package main import ( "fmt" "html/template" "net/http" "time" ) var layout *template.Template func main() { router := http.NewServeMux() server := &

我正在开发一个具有web服务器的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)
}
layout.html:
你好{{.}

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

我希望在超时后,func会立即结束,连接会关闭,浏览器会停止加载并显示错误


如何实现这一点?

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

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
    }
}
主程序包
进口(
“上下文”
“fmt”
“html/模板”
“net/http”
“时间”
)
var布局*template.template
var WriteTimeout=1*时间秒
func main(){
路由器:=http.NewServeMux()
服务器:=&http.server{
地址:“:8889”,
处理程序:路由器,
读取超时:5*次。秒,
WriteTimeout:WriteTimeout+10*time.毫秒,//10ms冗余时间
空闲时间:15*次。秒,
}
路由器.HandleFunc(“/”,主页)
server.listendServe()
}
func home(w http.ResponseWriter,r*http.Request){
fmt.Printf(“响应\n”)
ctx,:=context.WithTimeout(context.Background(),WriteTimeout)
工作者,取消:=上下文.WithCancel(context.Background())
变量缓冲字符串
go func(){
//做点什么
时间。睡眠(2*时间。秒)
buffer=“准备好所有响应\n”
//再做一次
时间。睡眠(2*时间。秒)
取消
fmt.Printf(“工人完成\n”)
}()
挑选{

案例“超时后”在哪里?您希望什么会导致处理程序“立即结束”?Go中没有任何东西可以强制正在运行的goroutine从goroutine外部停止。我猜WriteTimeout是一个触发器,因为它在没有睡眠的情况下工作。你是对的,这不是我期望的,而是我想要实现的。没有任何东西可以从外部停止处理程序。它只是一个函数,当它重新运行时会停止ns。如果您达到写入超时,Execute将返回一个错误。这里没有猜测。在localhost上使用普通浏览器时,您不太可能获得此超时。时间。睡眠是不可中断的,并且不是真正代码的好替代品,因此我们无法在此处提出相关建议。但为什么在运行服务器和vi时使用浏览器时,我在控制台上得到10个println(“响应”),然后浏览器显示连接重置错误?