49 lines
1.5 KiB
Go
49 lines
1.5 KiB
Go
package middleware
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime/debug"
|
|
"strings"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
"github.com/gogf/gf/v2/net/ghttp"
|
|
|
|
"easygoadmin/internal/consts"
|
|
"easygoadmin/utility/response"
|
|
)
|
|
|
|
// ============================== 统一响应兜底中间件 ==============================
|
|
|
|
// Response 统一响应兜底
|
|
//
|
|
// 负责 panic 恢复并输出统一 JSON 错误(前端契约 {code,msg,data}),
|
|
// 置于跨域之后、认证之前,保证任何环节的 panic 都不会泄漏堆栈到前端。
|
|
// 同时将请求元信息(IP、UA、方法、URL)写入上下文,供登录日志与操作日志采集。
|
|
func Response(r *ghttp.Request) {
|
|
// SVG 静态文件加固:强制附件下载 + nosniff(防内嵌脚本同源执行)
|
|
if strings.HasSuffix(strings.ToLower(r.URL.Path), ".svg") {
|
|
r.Response.Header().Set("Content-Disposition", "attachment")
|
|
r.Response.Header().Set("X-Content-Type-Options", "nosniff")
|
|
}
|
|
// 请求元信息(所有路由均需,登录日志依赖)
|
|
r.SetCtx(consts.WithRequestMeta(r.Context(),
|
|
realClientIP(r),
|
|
r.Header.Get("User-Agent"),
|
|
r.Method,
|
|
r.URL.String(),
|
|
))
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
g.Log().Errorf(r.Context(), "panic recovered: %v\n%s", e, debug.Stack())
|
|
if _, written := response.GetCode(r); written {
|
|
return // 已写出响应,仅记录
|
|
}
|
|
response.WriteWithCode(r,
|
|
response.Fail(gerror.NewCode(consts.CodeServerError, fmt.Sprintf("服务器内部错误: %v", e))),
|
|
500)
|
|
}
|
|
}()
|
|
r.Middleware.Next()
|
|
}
|