如何在HTTP服务器请求上实现60秒的上下文超时?一种类型的处理程序已经有了应用了值的上下文
我不知道如何以最好的方式实现它
找到这个答案https://stackoverflow.com/a/43322359/555222
如果超时,如何停止http请求处理程序继续执行?
实现前的原始代码
srv := &http.Server{
Addr: fmt.Sprintf("%s:%d", h.host, h.port),
Handler: http.HandlerFunc(h.serve),
}
err := srv.ListenAndServe()
...
func (h *HTTP) serve(w http.ResponseWriter, r *http.Request) {
var allow []string
for _, route := range h.routes {
if route.regex != nil {
// Regex path
matches := route.regex.FindStringSubmatch(r.URL.Path)
len := len(matches)
if len > 0 {
if len == 1 {
route.handler(w, r) // ADD CONTEXT TIMEOUT 60 SECS
}else{
// Context with value
ctx := context.WithValue(r.Context(), ctx_http, matches[1:])
route.handler(w, r.WithContext(ctx)) // ADD CONTEXT TIMEOUT 60 SECS
}
return
}
}else{
// Path
if strings.HasPrefix(r.URL.Path, route.path) {
route.handler(w, r) // ADD CONTEXT TIMEOUT 60 SECS
return
}
}
}
http.Error(w, "Not found", http.StatusNotFound)
}
实现后的代码(不工作)
这是我所期望的工作
- 在http请求处理程序中休眠10秒
- 2秒上下文超时
什么管用 - 如果请求超时超过2秒,则返回
HTTP 408
,并关闭连接(如预期)
什么行不通 - 如果请求超过了超时时间,http请求处理程序将继续执行,并在超时后8秒打印
req executed
输出
2023-08-28 20:14:47 context timeout exceeded
2023-08-28 20:14:47 cancel
2023-08-28 20:14:55 req completed
代码
func (h *HTTP) serve(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), time.Duration(2 * time.Second))
defer func(){
fmt.Println(time.Now(), "cancel")
cancel()
}()
go func(){
for _, route := range h.routes {
if route.regex != nil {
// Regex path
matches := route.regex.FindStringSubmatch(r.URL.Path)
len := len(matches)
if len > 0 {
// Slug group capture
if len > 1 {
ctx = context.WithValue(ctx, ctx_http, matches[1:])
}
route.handler(w, r.WithContext(ctx))
cancel()
return
}
}else{
// Path
if strings.HasPrefix(r.URL.Path, route.path) {
route.handler(w, r.WithContext(ctx))
cancel()
return
}
}
}
http.Error(w, "Not found", http.StatusNotFound)
cancel()
}()
select {
case <-ctx.Done():
switch ctx.Err() {
case context.DeadlineExceeded:
fmt.Println(time.Now(), "context timeout exceeded")
http.Error(w, "Timeout", http.StatusRequestTimeout)
case context.Canceled:
fmt.Println(time.Now(), "context cancelled by force. whole process is complete")
}
}
}
HTTP请求处理程序
h.Route(serv.ALL, "/timeout", func(w http.ResponseWriter, r *http.Request){
defer serv.Recover(w)
time.Sleep(10 * time.Second)
fmt.Println(time.Now(), "req completed")
io.WriteString(w, "timeout test")
})
2条答案
按热度按时间m0rkklqb1#
这个问题明确地询问了关于创建超时上下文的问题,但是OP的注解表明他们希望在不使用上下文的情况下使请求超时。要做到这一点,在OP的原始代码中使用超时处理程序 Package 根处理程序:
这是对所提问题的回答。
使用以下代码实现HTTP请求的上下文超时:
在处理程序中使用上下文:
jc3wubiy2#
您可以使用WithTimout将Timeout添加到上下文,并可以使用
r.WithContext(ctx)
将上下文传递给请求,就像您在其中一个案例中所做的那样。