我想知道为 Echo 库上的特定路线设置超时的最佳方法。
我用context.WithTimeout实现了超时,但使用了几个函数来封装上下文,我认为这是错误的。
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
是否有任何中间件或更好的方法来实现这一点?
最佳答案
向服务器 context.Context 添加超时
在不确切知道您要做什么的情况下回答这个问题有点棘手。我将首先回答如何使用 WithTimeout
和中间件来处理上下文包装。
中间件可以添加/修改请求上下文,如下所示:
func TimeoutMiddleware(timeout time.Duration, next func(w http.ResponseWriter, req *http.Request)) func(w http.ResponseWriter, req *http.Request) {
return func(w http.ResponseWriter, req *http.Request) {
// Wrap the existing context from the request
ctx, cancel := context.WithTimeout(req.Context(), timeout)
// Always do this to clean up contexts, otherwise they'll hang out
// and gather since they are blocked go rountines
defer cancel()
// Put the new context into the request
req = req.WithContext(ctx)
// Pass the modified request forward
next(w, req)
// Handle any ctx timeout issues in the general middleware
if err := ctx.Err(); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
log.Println("HTTP Request timed out")
w.Write([]byte("Timed out"))
}
}
}
}
问题是 next(w, req)
需要您的 http 处理程序来处理上下文超时。如果 http 处理程序忽略上下文,则不会超时。比如这样:
func endless(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
// Just a busy loop....
for {
select {
case <-ctx.Done():
// Exit the handler if the context is Done(), even if our function is not.
return
default:
fmt.Println("wait")
time.Sleep(1 * time.Second)
}
}
}
如果您正在进行数据库调用或需要在处理程序中花费时间的操作,通常数据库 API 会接受 context.Context
以便在上下文被取消时提前中止。
因此,此解决方案为进入处理程序的请求上下文添加了超时,您仍然需要管理该处理程序。
客户端超时
您始终可以将超时添加到您的请求中:
client := http.Client{
Timeout: time.Second,
}
client.Do(...)
关于go - 在 Echo/Go 上实现特定路线超时的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65972668/