以下是示例
package main
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
)
// TimeoutMiddleware wraps the request context with a timeout
func TimeoutMiddleware(timeout time.Duration) func(c *gin.Context) {
return func(c *gin.Context) {
// wrap the request context with a timeout
ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
defer func() {
// check if context timeout was reached
if ctx.Err() == context.DeadlineExceeded {
// write response and abort the request
c.Writer.WriteHeader(http.StatusGatewayTimeout)
c.Abort()
}
//c.JSON(http.StatusOK, "请求超时")
cancel()
}()
// replace request with context wrapped request
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
// timedHandler 模拟实际项目中的handler
func timedHandler(duration time.Duration) func(c *gin.Context) {
return func(c *gin.Context) {
// get the underlying request context
ctx := c.Request.Context()
// create the response data type to use as a channel type
type responseData struct {
status int
body map[string]interface{}
}
// create a done channel to tell the request it's done
doneChan := make(chan responseData)
// here you put the actual work needed for the request
// and then send the doneChan with the status and body
// to finish the request by writing the response
go func() {
time.Sleep(duration)
doneChan <- responseData{
status: 200,
body: gin.H{"hello": "world"},
}
}()
// non-blocking select on two channels see if the request
// times out or finishes
select {
// if the context is done it timed out or was cancelled
// so don't return anything
case <-ctx.Done():
fmt.Println(ctx.Err())
return
// if the request finished then finish the request by
// writing the response
case res := <-doneChan:
c.JSON(res.status, res.body)
}
}
}
func main() {
engine := gin.New()
engine.Use(TimeoutMiddleware(time.Second * 2))
engine.GET("/normal", timedHandler(time.Second))
engine.GET("/exceed", timedHandler(time.Second*5))
log.Fatal(engine.Run(":8088"))
}
curl localhost:8089/normalcurl localhost:8089/exceed