29

golang http server如何设置request的context超时

 3 years ago
source link: https://studygolang.com/articles/31361
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

main函数

func main() {
    address := fmt.Sprintf("%s:%d", "0.0.0.0", 8080)
    router  := mux.NewRouter().StrictSlash(true)

    router.HandleFunc("/api/hello", handler)
    err := http.ListenAndServe(address, router)
    if err != nil {
        log.Panic("ListenAndServe err:", err)
    }
}

handler函数

func handler(w http.ResponseWriter, r *http.Request) {
    log.Printf("Request is coming\n")
    var userId string
    if queryParams, ok := r.URL.Query()["user"]; ok && len(queryParams) > 0 {
        userId = queryParams[0]
    }

    // handle context timeout
    var ctx context.Context
    var cancel context.CancelFunc
    if queryParams, ok  := r.URL.Query()["timeout"]; ok && len(queryParams) > 0 {
        timeout, err := time.ParseDuration(queryParams[0])
        if err != nil {
            ctx, cancel = context.WithCancel(r.Context())
        } else {
            ctx, cancel = context.WithTimeout(r.Context(), timeout)
        }
    } else {
        ctx, cancel = context.WithCancel(r.Context())
    }
    defer cancel()

    // call implementation function
    result, err := GetUser(ctx, userId)
    if err != nil {
        log.Printf("Request is return with error: %v\n", err)
        writeErrorResponse(http.StatusInternalServerError, err, w)
        return
    }

    log.Printf("Request is return with success\n")
    writeResponse(http.StatusOK, result, w)
}

在handler函数里面从r.Context生成一个新的context,并传递给功能函数GetUser(ctx context).

功能函数

func GetUser(ctx context.Context, userId string) (map[string]string, error) {
    c := make(chan interface{}, 1)

    go func() {
        time.Sleep(10 * time.Second)

        c <- "123-456-7890"
    } ()

    select {
    case <-ctx.Done():
        log.Printf("Context interrupt or timeout: %v\n", ctx.Err())
        return nil, fmt.Errorf("Context interrupt or timeout: %v", ctx.Err())
    case result := <-c:
        return map[string]string{"name":userId, "phone": result.(string)}, nil
    }
}

在功能函数里面,异步方式调用起来具体的实现功能,然后等待在ctx.Done()或者c里面有数据。

  • ctx.Done返回如果满足:
    -- client放弃请求,或者
    -- 超时,根据参数timeout设置的超时
  • c里面有数据,则表示具体的实现功能函数完成,在这里例子里是匿名函数执行返回。

使用curl工具发起client请求:

  1. curl localhost:8080/api/hello
    正常请求,10秒后返回
  2. curl localhost:8080/api/hello + ctrl-C
    用户ctrl-C杀掉curl命令
  3. curl --max-time 5 localhost:8080/api/hello
    客户端设置5秒超时

有疑问加站长微信联系

iiUfA3j.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK