http中间件中的Go和指针
Go and Pointers in http middleware
我试图在我的网络服务器上记录一些数据,所以我创建了一个 loggingMiddleware
服务于下一个请求,然后记录数据,我想这样我会在里面有所有必要的数据r *http.Request
指针
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 returns a shallow copy of r with its context changed to
ctx. The provided ctx must be non-nil.
因此,因为它是“returns r 的浅拷贝”,并且它是(指向)它传递给 next.ServeHTTP
的浅拷贝,如果 middleware.RequestID
是第二个挂载,然后 LoggingMiddleware
中的 r
指向与包含修改后的上下文的 *http.Request
不同的 *http.Request
,因此其上下文将不包含请求 ID。另一方面,如果先挂载 middleware.RequestID
,则 LoggingMiddleware
将收到指向 r.WithContext
返回的浅表副本的指针,一切都会按预期工作。
我试图在我的网络服务器上记录一些数据,所以我创建了一个 loggingMiddleware
服务于下一个请求,然后记录数据,我想这样我会在里面有所有必要的数据r *http.Request
指针
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
:
ctx = context.WithValue(ctx, RequestIDKey, requestID)
next.ServeHTTP(w, r.WithContext(ctx))
根据文档:
WithContext returns a shallow copy of r with its context changed to ctx. The provided ctx must be non-nil.
因此,因为它是“returns r 的浅拷贝”,并且它是(指向)它传递给 next.ServeHTTP
的浅拷贝,如果 middleware.RequestID
是第二个挂载,然后 LoggingMiddleware
中的 r
指向与包含修改后的上下文的 *http.Request
不同的 *http.Request
,因此其上下文将不包含请求 ID。另一方面,如果先挂载 middleware.RequestID
,则 LoggingMiddleware
将收到指向 r.WithContext
返回的浅表副本的指针,一切都会按预期工作。