英文:
How to Add/Set Header after next() in Golang Echo Middleware?
问题
主要目的:
我想简单地计算任何API/路由的执行时间,并将其添加到响应头中,键为ExecutionTime。
我非常愿意尝试其他方法,因为我对Go-Echo框架还不熟悉,我的方法可能是错误的。
我一直在做什么:
这是我的中间件代码:
func (s *Stats) ExecTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
c.Response().Header().Set("ExecutionStartedAt", time.Now().String())
if err := next(c); err != nil { //执行主要过程
c.Error(err)
}
c.Response().Header().Set("ExecutionDoneAt", time.Now().String())
return nil
}
}
当前结果:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Executionstartedat: 2022-09-11 16:32:15.612045 +0700 WIB m=+3.619364986
< Server: Echo/3.0
< Date: Sun, 11 Sep 2022 09:32:21 GMT
< Content-Length: 856
请注意:已添加了Executionstartedat。但不幸的是,没有像预期的那样添加ExecutionDoneAt。
期望的结果:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Executionstartedat: 2022-09-11 16:32:15.612045 +0700 WIB m=+3.619364986
< Executiondoneat: 2022-09-11 16:32:18.612045 +0700 WIB m=+3.619364986
< Server: Echo/3.0
< Date: Sun, 11 Sep 2022 09:32:21 GMT
< Content-Length: 856
我正在遵循这个文档:https://echo.labstack.com/cookbook/middleware/#response
非常感谢任何帮助、任何想法、任何实现相同结果的替代方法。非常感谢。
编辑 #1:
我还尝试了什么:
我尝试使用另一个中间件,计时是正确的,就像我预期的那样。但不幸的是,头部仍然为空。
e.Use(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {
fmt.Println("this is from BodyDump 7: ", time.Now())
c.Response().Header().Set("ExecutionTime7", "Exec Time: " + time.Now().String())
}))
结果与上面完全相同,没有任何变化。
编辑 #2
这是一个可工作的代码示例:
// ExecTime是中间件函数。
func (s *Stats) ExecTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
before := time.Now()
c.Response().Header().Set("ExecutionStartedAt", before.String())
c.Response().Before(func() {
after := time.Now()
elapsed := time.Since(before)
c.Response().Header().Set("ExecutionDoneAt", after.String())
c.Response().Header().Set("ExecutionTime", elapsed.String())
})
if err := next(c); err != nil { //执行主要过程
c.Error(err)
}
return nil
}
}
英文:
Main Purpose:
I want to simply count the execution time for any API / route, and add it into the Response Header with key: ExecutionTime.
I am very open to another alternative, since my method may wrong as I am still new in Go-Echo framework.
What I have been doing:
So this is my middleware code:
func (s *Stats) ExecTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
c.Response().Header().Set("ExecutionStartedAt", time.Now().String())
if err := next(c); err != nil { //exec main process
c.Error(err)
}
c.Response().Header().Set("ExecutionDoneAt", time.Now().String())
return nil
}
}
Current Result:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Executionstartedat: 2022-09-11 16:32:15.612045 +0700 WIB m=+3.619364986
< Server: Echo/3.0
< Date: Sun, 11 Sep 2022 09:32:21 GMT
< Content-Length: 856
Please note: There is an Executionstartedat added. But unfortunatelly there is no ExecutionDoneAt as expected.
Expected Result:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=UTF-8
< Executionstartedat: 2022-09-11 16:32:15.612045 +0700 WIB m=+3.619364986
< Executiondoneat: 2022-09-11 16:32:18.612045 +0700 WIB m=+3.619364986
< Server: Echo/3.0
< Date: Sun, 11 Sep 2022 09:32:21 GMT
< Content-Length: 856
I am following this documentation: <https://echo.labstack.com/cookbook/middleware/#response>
Any help, any idea, any alternative ways to accomplish same result would be very very appreciated. Thank you very much.
Edited #1:
What else I have tried:
I have tried to use another middleware, the timing is good, just as I expected. But unfortunately the header is still empty.
e.Use(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {
fmt.Println("this is from BodyDump 7: ", time.Now())
c.Response().Header().Set("ExecutionTime7", "Exec Time: " + time.Now().String())
}))
The result is exactly like above, no change at all.
Edited #2
here is the working code example:
// ExecTime is the middleware function.
func (s *Stats) ExecTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
before := time.Now()
c.Response().Header().Set("ExecutionStartedAt", before.String())
c.Response().Before(func() {
after := time.Now()
elapsed := time.Since(before)
c.Response().Header().Set("ExecutionDoneAt", after.String())
c.Response().Header().Set("ExecutionTime", elapsed.String())
})
if err := next(c); err != nil { //exec main process
c.Error(err)
}
return nil
}
}
答案1
得分: 3
在HTTP中,头部在正文之前,正如“header”这个名字所暗示的那样。因此,一旦你写了正文,就不能再写头部了。你可以尝试使用HTTP/2的Trailers。或者在执行过程中,在将其输出写入正文之前,计算执行时间,添加头部,然后再写入正文。
我不使用echo
,所以我不知道正确的方法是什么,但我觉得如果你在使用响应之前使用响应的before hook可能会更好。
以下是@JackySupit提供的示例:
// ExecTime是中间件函数。
func (s *Stats) ExecTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
before := time.Now()
c.Response().Header().Set("ExecutionStartedAt", before.String())
c.Response().Before(func() {
after := time.Now()
elapsed := time.Since(before)
c.Response().Header().Set("ExecutionDoneAt", after.String())
c.Response().Header().Set("ExecutionTime", elapsed.String())
})
if err := next(c); err != nil { //执行主要过程
c.Error(err)
}
return nil
}
}
英文:
In HTTP the headers go before the body, as the name "header" implies. So once you write the body you cannot write the header. You may try using HTTP/2 Trailers. Or execute the process, but before writing its output to the body, calculate the execution time, add the header, and then write the body.
I don't use echo
so I don't know what the correct approach is, but it seems to me like it'd be better if you use the response before hook.
Example by @JackySupit:
// ExecTime is the middleware function.
func (s *Stats) ExecTime(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
before := time.Now()
c.Response().Header().Set("ExecutionStartedAt", before.String())
c.Response().Before(func() {
after := time.Now()
elapsed := time.Since(before)
c.Response().Header().Set("ExecutionDoneAt", after.String())
c.Response().Header().Set("ExecutionTime", elapsed.String())
})
if err := next(c); err != nil { //exec main process
c.Error(err)
}
return nil
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论