超时
超时中间件有两种不同的实现 Fiber。
新
用超时包装 fiber.Handler
。如果处理程序花费的时间超过给定的持续时间,则设置超时错误并将其转发到集中式 ErrorHandler。
注意
由于会引发竞争条件,此方法已被弃用。
NewWithContext
作为 fiber.Handler
包装器,它使用 context.WithTimeout
创建一个上下文,并将其传递到 UserContext
中。
如果传递的上下文执行(例如数据库操作、HTTP 调用)花费的时间超过给定的持续时间,则设置超时错误并将其转发到集中式 ErrorHandler
。
它不会取消长时间运行的执行。底层执行必须使用 context.Context
参数来处理超时。
签名
func New(handler fiber.Handler, timeout time.Duration, timeoutErrors ...error) fiber.Handler
func NewWithContext(handler fiber.Handler, timeout time.Duration, timeoutErrors ...error) fiber.Handler
示例
导入 Fiber Web 框架的一部分中间件包
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/timeout"
)
在启动 Fiber 应用程序后,你可以使用以下可能性
func main() {
app := fiber.New()
h := func(c *fiber.Ctx) error {
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
if err := sleepWithContext(c.UserContext(), sleepTime); err != nil {
return fmt.Errorf("%w: execution error", err)
}
return nil
}
app.Get("/foo/:sleepTime", timeout.New(h, 2*time.Second))
log.Fatal(app.Listen(":3000"))
}
func sleepWithContext(ctx context.Context, d time.Duration) error {
timer := time.NewTimer(d)
select {
case <-ctx.Done():
if !timer.Stop() {
<-timer.C
}
return context.DeadlineExceeded
case <-timer.C:
}
return nil
}
使用 curl 测试 http 200
curl --location -I --request GET 'https://127.0.0.1:3000/foo/1000'
使用 curl 测试 http 408
curl --location -I --request GET 'https://127.0.0.1:3000/foo/3000'
与自定义错误一起使用
var ErrFooTimeOut = errors.New("foo context canceled")
func main() {
app := fiber.New()
h := func(c *fiber.Ctx) error {
sleepTime, _ := time.ParseDuration(c.Params("sleepTime") + "ms")
if err := sleepWithContextWithCustomError(c.UserContext(), sleepTime); err != nil {
return fmt.Errorf("%w: execution error", err)
}
return nil
}
app.Get("/foo/:sleepTime", timeout.NewWithContext(h, 2*time.Second, ErrFooTimeOut))
log.Fatal(app.Listen(":3000"))
}
func sleepWithContextWithCustomError(ctx context.Context, d time.Duration) error {
timer := time.NewTimer(d)
select {
case <-ctx.Done():
if !timer.Stop() {
<-timer.C
}
return ErrFooTimeOut
case <-timer.C:
}
return nil
}
使用数据库调用的示例
func main() {
app := fiber.New()
db, _ := gorm.Open(postgres.Open("postgres://127.0.0.1/foodb"), &gorm.Config{})
handler := func(ctx *fiber.Ctx) error {
tran := db.WithContext(ctx.UserContext()).Begin()
if tran = tran.Exec("SELECT pg_sleep(50)"); tran.Error != nil {
return tran.Error
}
if tran = tran.Commit(); tran.Error != nil {
return tran.Error
}
return nil
}
app.Get("/foo", timeout.NewWithContext(handler, 10*time.Second))
log.Fatal(app.Listen(":3000"))
}