Comments (19)
Hi guys, after all those years, I bump into the same problem here! any cleaner solutions with middleware to write the x-response-sent
header?
from gin.
I would like this same feature. It should be simple to implement.
from gin.
I opened a pull request to add this.
#89
from gin.
That's what i wanted!
from gin.
👍
from gin.
hi guys! I am back. we may need to fix this issue in a different way.
I meant, Before() is a way to had around how the net library works, I do not think the API should be designed in that way. The APIs should not be implementation dependent.
The developer should not know that they have to use Before()...
I propose to defer the call to write.WriteHeader() just before we write to the socket.
So for example:
c.WriteHeader(404) --> caches 404
c.WriteHeader(200) --> caches 200
c.Write(stuff) ---> write headers & write stuff
c.Write(moreStuff) --> write more stuff
If c.Write() is never called in the "user-land", internally Gin would write the headers manually.
from gin.
Check this out: dcafad3
from gin.
I agree that this is a better solution. I was just doing what martini does without exploring other approaches.
from gin.
I have been testing this so far and in fact it fixes several bugs in our backend, sounds like a good fix.
Is everybody ok? are there any use case where Before()
could be needed?
from gin.
Agree that it should be transparent and this sounds as a good solution so far
from gin.
Would we also be able to defer the write in Abort? I ran into a case where I was calling abort, but in a clean-up middleware was capturing and transforming the error and calling c.JSON(200,...) - that ends up calling WriteHeader twice - first time in Abort. If it also deferred until all code had run, I could transform it in middleware.
from gin.
Yes, the current version also defers Abort()
so, if you call, c.Abort(400)
, and then you can c.JSON(200, info)
. The final response would be 200.
And WriteHeader() is called once! does it work for you?
I will add a new function to Context, so you can know if Abort() was already called.
Context.Aborted() bool
from gin.
Fantastic! Many thanks.
from gin.
@manucorporat Can you share an example? After reading the thread I still don't understand how to implement the logic for middleware that would add a header as soon as it gets the request and also right before sending the response (for logging performance from the client). Is this possible?
Here's what I have:
func latencyHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
now := time.Now()
timestamp := strconv.FormatInt(now.UnixNano() / 1000000, 10)
c.Writer.Header().Set("x-request-received", timestamp)
c.Next()
}
}
from gin.
@montanaflynn here you have it:
package main
import (
"net/http"
"time"
"strconv"
"github.com/gin-gonic/gin"
)
func main() {
g := gin.New()
latencyHandler := func(c *gin.Context) {
now := time.Now()
timestamp := strconv.FormatInt(now.UnixNano() / 1000000, 10)
c.Writer.Header().Set("x-request-received", timestamp)
c.Next()
}
// Logging middleware
g.Use(gin.Logger())
// Enable the custom latency middleware, must come before recovery
g.Use(latencyHandler)
// Recovery middleware
g.Use(gin.Recovery())
g.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello World!")
})
// Serve
g.Run(":3000")
}
from gin.
@javierprovecho thanks for taking the time to help me out although I don't think I was clear enough in my request. What I would like is to have my middleware add the x-request-received
header as soon as it gets the request but also add a second header x-response-sent
right before sending the response.
Here's an example that works but I'd like to add the x-response-sent
header in the middleware.
package main
import (
"net/http"
"time"
"strconv"
"github.com/gin-gonic/gin"
)
func main() {
g := gin.New()
latencyHandler := func(c *gin.Context) {
now := time.Now()
timestamp := strconv.FormatInt(now.UnixNano() / 1000000, 10)
c.Writer.Header().Set("x-request-received", timestamp)
c.Next()
}
// Enable the custom latency middleware, must come before recovery
g.Use(latencyHandler)
// Logging middleware
g.Use(gin.Logger())
// Recovery middleware
g.Use(gin.Recovery())
g.GET("/", func(c *gin.Context) {
// Simulate processing time
time.Sleep(5 * time.Second)
now := time.Now()
timestamp := strconv.FormatInt(now.UnixNano() / 1000000, 10)
c.Writer.Header().Set("x-response-sent", timestamp)
c.String(http.StatusOK, "Hello World!")
})
// Serve
g.Run(":3000")
}
from gin.
Well, due to the nature of Gin and its buffer-less response the only way to do it is to call a second function passing the context as argument and doing the same as the first function, latencyHandler.
g.GET("/", func(c *gin.Context) {
// Simulate processing time
time.Sleep(5 * time.Second)
latencyHandler2(c)
c.String(http.StatusOK, "Hello World!")
})
latencyHandler2 := func(c *gin.Context) {
now := time.Now()
timestamp := strconv.FormatInt(now.UnixNano() / 1000000, 10)
c.Writer.Header().Set("x-response-sent", timestamp)
}
As said you can't create a middleware that attach a new header after sending body.
from gin.
Bummer, I think this hits on when @manucorporat asked if there was any need for a Before() method.
In other languages these are often referred to as "hooks". So you could have your middleware hook into the final Write for instance and only execute the given function at that time. I have no idea how this would look in Go or if suitable for Gin.
@javierprovecho thanks for your help
from gin.
Hey everyone. Here is how I eventually solved the problem:
https://gist.github.com/luza/dca5936637f525848d67e49e21820f93
Hope it will help.
from gin.
Related Issues (20)
- The binding:"required" tag does not seem to work for struct types HOT 3
- Is there a way to preserve order in JSON on response? HOT 1
- redirect is not success HOT 1
- I want to use shouldmindbodywith first and then use formafile, but it doesn't work right now HOT 3
- Extend the routing tree entry
- Transparent decompression for gzip, deflate, etc? HOT 1
- Custom time.Time type can not use bindQuery get a value 2 HOT 2
- http: response.Write on hijacked connection from github.com/gin-gonic/gin.(*responseWriter).Write (response_writer.go:83) HOT 1
- Suggestion: Move Print Debug to Run() functions? HOT 7
- AbortWithStatusJSON doesn't abort context HOT 2
- I translated `tree.go` into java
- GetUint and GetUint64 wrong return HOT 1
- Multipart form-data request with empty key for single file upload
- gin with golang 1.21, 1.22 DATA RACE
- gin detects `DATA RACE` with Go1.21, Go1.22 HOT 7
- Please consider remove github.com/bytedance/sonic from dependencies HOT 4
- send response from middleware, continue to execute handler chain HOT 3
- StringToBytes is slower than the raw convertion
- Bind recursion struct param fatal exit
- Warning link doesn't point to anything anymore HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gin.