kra/internal/server/middleware/gin_recovery.go

99 lines
2.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package middleware
import (
"net"
"net/http"
"net/http/httputil"
"os"
"runtime/debug"
"strings"
"kra/pkg/response"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// 全局日志实例
var recoveryLogger *zap.Logger
// SetRecoveryLogger 设置Recovery日志
func SetRecoveryLogger(logger *zap.Logger) {
recoveryLogger = logger
}
// GinRecovery 自定义Recovery中间件与 kra 保持一致)
func GinRecovery(stack bool) gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
// 检查是否为断开的连接
var brokenPipe bool
if ne, ok := err.(*net.OpError); ok {
if se, ok := ne.Err.(*os.SyscallError); ok {
if strings.Contains(strings.ToLower(se.Error()), "broken pipe") ||
strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
brokenPipe = true
}
}
}
httpRequest, _ := httputil.DumpRequest(c.Request, false)
if brokenPipe {
if recoveryLogger != nil {
recoveryLogger.Error(c.Request.URL.Path,
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
}
// 如果连接已断开,无法写入状态
c.Error(err.(error))
c.Abort()
return
}
if stack {
if recoveryLogger != nil {
recoveryLogger.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
zap.String("stack", string(debug.Stack())),
)
}
} else {
if recoveryLogger != nil {
recoveryLogger.Error("[Recovery from panic]",
zap.Any("error", err),
zap.String("request", string(httpRequest)),
)
}
}
response.FailWithMessage("服务器内部错误", c)
c.Abort()
}
}()
c.Next()
}
}
// Cors 跨域中间件
func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin")
c.Header("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token,Authorization,Token,X-Token,X-User-Id")
c.Header("Access-Control-Allow-Methods", "POST,GET,OPTIONS,DELETE,PUT")
c.Header("Access-Control-Expose-Headers", "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers,Content-Type,New-Token,New-Expires-At")
c.Header("Access-Control-Allow-Credentials", "true")
// 放行所有OPTIONS方法
if method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
}
c.Next()
}
}