问题描述
我试图在我的网络服务器上记录一些数据,所以我创建了一个 loggingMiddleware
来为下一个请求提供服务,然后记录数据,我想这样我就会在 r *http.Request
中包含所有必要的数据{1}} 指针
return http.HandlerFunc(func(w http.ResponseWriter,r *http.Request) {
// call next handler
next.ServeHTTP(o,r)
// get requestID
reqID := middleware.GetReqID(r.Context())
log.WithFields(
log.Fields{
"request_id": reqID,// drops requestID
"method": r.Method,// http method
"remote_address": r.RemoteAddr,// remote address
"url": r.URL.String(),// url used by the client to access the service
"referer": r.Referer(),// Referer header if present
"user_agent": r.UserAgent(),// User-Agent header
"content_length": r.ContentLength,// Content-Length header if present"
},).Info()
})
然而,对于 RequestID,只有 RequestID
中间件安装在 loggingMiddleware 之前才是正确的
非工作
...
// get a new chi rotuter
router = chi.NewRouter()
// MIDDLEWARES
// log
// use logrus to log requests
router.Use(LoggingMiddleware)
// requestID
// Generate a unique id for every request
// ids are grouped based on client hostname
router.Use(middleware.RequestID)
...
工作
...
// get a new chi rotuter
router = chi.NewRouter()
// MIDDLEWARES
// requestID
// Generate a unique id for every request
// ids are grouped based on client hostname
router.Use(middleware.RequestID)
// log
// use logrus to log requests
router.Use(LoggingMiddleware)
...
这是预期的行为吗? r *http.Request
指针是否应该指向请求的“更新”版本?有没有办法解决这个问题?
因为,例如,如果我想从 JWT 令牌中提取用户名并将其放入 r.Context()
以便我可以稍后记录它,这将需要在 loggingMiddleware
之前安装一个单独的中间件。
对不起,我的英语不好,请询问是否有不清楚的地方。
谢谢
解决方法
middleware.RequestID
使用 http.Request.WithContext
将请求 ID 添加到请求上下文:
ctx = context.WithValue(ctx,RequestIDKey,requestID)
next.ServeHTTP(w,r.WithContext(ctx))
根据文档:
WithContext 返回 r 的浅拷贝,其上下文更改为 ctx。提供的 ctx 必须非 nil。
因此,因为它“返回 r 的浅拷贝”,并且它是(指向)这个浅拷贝传递给 next.ServeHTTP
,如果 middleware.RequestID
被第二次挂载,那么 { r
中的 {1}} 指向的 LoggingMiddleware
与包含修改上下文的 *http.Request
不同,因此其上下文将不包含请求 ID。另一方面,如果 middleware.RequestID
首先被挂载,那么 LoggingMiddleware
将收到一个指向 r.WithContext
返回的浅拷贝的指针,并且一切都会按预期进行。