跳至主要内容
版本:v2.x

超时

超时中间件有两种不同的实现 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"))
}