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请求:
- curl localhost:8080/api/hello
正常请求,10秒后返回 - curl localhost:8080/api/hello + ctrl-C
用户ctrl-C杀掉curl命令 - curl --max-time 5 localhost:8080/api/hello
客户端设置5秒超时
有疑问加站长微信联系(非本文作者)