在 martini 框架中,可通过为 `recoverwrap` 中间件函数添加 `*http.request` 参数,直接注入并访问 `req.url.path` 或完整 url,从而在 panic 恢复时准确记录出错路径(如 `/panic`),便于错误追踪与告警。
Martini 采用依赖注入机制,中间件函数的参数会由框架自动解析并注入对应类型的实例。*http.Request 正是可被自动注入的标准类型之一——只要将其声明为 RecoverWrap 函数的参数,即可在 defer 恢复逻辑中安全使用。
以下是一个完整、可运行的示例,展示了如何在 panic 捕获阶段获取并打印请求 URL:
package main
import (
"errors"
"fmt"
"github.com/go-martini/martini"
"net/http"
)
func main() {
m := martini.Classic()
m.Use(RecoverWrap)
m.Get("/panic", func() {
panic("some panic")
})
m.Get("/", func(res http.ResponseWriter) {
res.Write([]byte("mainPage"))
})
m.Run()
}
func RecoverWrap(c martini.Context, req *http.Request, w http.ResponseWriter) {
var err error
defer func(w http.ResponseWriter) {
r := recover()
if r != nil {
switch t := r.(type) {
case string:
err = errors.New(t)
case error:
err = t
default:
err = errors.New("Unknown error")
}
// ✅ 安全获取当前请求路径
fullPath := req.URL.Path
query := req.URL.RawQuery
fullURL := req.URL.String() // 包含 scheme/host(需注意:本地开发时可能为 /path?...,实际部署建议结合 req.Host 和 req.TLS 判断)
fmt.Printf("❌ Panic occurred at URL: %s\n", fullURL)
fmt.Printf(" Path: %s, Query: %s\n", fullPath, query)
// 示例:此处可集成邮件发送逻辑(如使用 net/s
mtp)
// sendAlertEmail(fmt.Sprintf("Panic on %s: %v", fullURL, err))
http.Error(w, "Something went wrong", http.StatusInternalServerError)
}
}(w)
c.Next()
}⚠️ 注意事项:
通过这一方式,你不仅能精准定位异常发生的路由,还能将 req 扩展用于日志上下文、用户标识、IP 记录等运维增强场景,显著提升错误排查效率。