Golang中使用超时、截止时间和上下文取消构建健壮的net/http服务器

Golang中使用超时、截止时间和上下文取消构建健壮的net/http服务器 卡片图片

使用超时、截止时间和上下文取消构建健壮的 Go net/http 服务器

当谈到超时时,有两种人:一种是知道它们有多棘手的人,另一种是尚未发现这一点的人。 尽管很棘手,但超时是我们所处的互联世界中的一个现实。就在我写这篇文章的时候,在另一…

也许你们中的一些人会觉得这很有趣 🙂


更多关于Golang中使用超时、截止时间和上下文取消构建健壮的net/http服务器的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中使用超时、截止时间和上下文取消构建健壮的net/http服务器的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中构建健壮的HTTP服务器时,正确设置超时、截止时间和上下文取消至关重要。以下是关键配置示例:

package main

import (
    "context"
    "net/http"
    "time"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // 模拟长时间运行的操作
        ctx := r.Context()
        select {
        case <-time.After(5 * time.Second):
            w.Write([]byte("请求完成"))
        case <-ctx.Done():
            // 客户端取消或超时
            http.Error(w, "请求超时", http.StatusRequestTimeout)
        }
    })

    server := &http.Server{
        Addr:         ":8080",
        Handler:      mux,
        ReadTimeout:  5 * time.Second,      // 读取整个请求的超时
        WriteTimeout: 10 * time.Second,     // 写入响应的超时
        IdleTimeout:  120 * time.Second,    // 空闲连接超时
    }

    // 使用带超时的上下文启动服务器
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    // 优雅关闭
    go func() {
        <-ctx.Done()
        shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
        defer shutdownCancel()
        server.Shutdown(shutdownCtx)
    }()

    server.ListenAndServe()
}

对于处理程序级别的超时控制:

func handlerWithTimeout(w http.ResponseWriter, r *http.Request) {
    ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
    defer cancel()

    // 将上下文传递给下游操作
    resultCh := make(chan string, 1)
    go func() {
        resultCh <- expensiveOperation(ctx)
    }()

    select {
    case result := <-resultCh:
        w.Write([]byte(result))
    case <-ctx.Done():
        http.Error(w, "处理超时", http.StatusGatewayTimeout)
    }
}

func expensiveOperation(ctx context.Context) string {
    // 检查上下文是否已取消
    if err := ctx.Err(); err != nil {
        return ""
    }
    
    // 执行耗时操作,定期检查上下文
    for i := 0; i < 10; i++ {
        select {
        case <-ctx.Done():
            return "已取消"
        case <-time.After(500 * time.Millisecond):
            // 继续处理
        }
    }
    return "完成"
}

对于客户端请求,设置请求超时:

func makeRequest() {
    client := &http.Client{
        Timeout: 10 * time.Second, // 整个请求的超时时间
    }

    req, _ := http.NewRequest("GET", "http://example.com", nil)
    
    // 设置请求级别的超时上下文
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    
    req = req.WithContext(ctx)
    
    resp, err := client.Do(req)
    if err != nil {
        // 处理超时或取消错误
        return
    }
    defer resp.Body.Close()
}

这些配置确保了服务器在面对慢客户端、网络问题或资源竞争时能够保持稳定。关键点包括:设置适当的服务器级超时、在处理程序中使用上下文传播取消信号、以及为客户端请求配置超时。

回到顶部