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)
- unexpected EOF during install HOT 1
- sse panic on fasthttphandler HOT 1
- Will it be made into a more comprehensive framework later on? HOT 4
- How does the gin close the log file? HOT 3
- Should we use url.PathUnescape instead of url.QueryUnescape when UnescapePathValues is true
- go get failed: The requested name is valid, but no data of the requested type was found HOT 1
- Attach Response Headers (or middlewares) to redirected requests (CORS issues) HOT 1
- Should context.GetRawData() also copy body to BodyBytesKey? HOT 3
- YAML BindBody should not parse JSON content HOT 1
- Gin do not support javascript ? HOT 5
- Does gin.Recovery() run before or after Group middleware? HOT 1
- How can i prevent a http connection to close HOT 3
- BasicAuth is not suitable for proxy auth
- Can't get status as expected from context.Status() HOT 1
- Gin Context implementation breaks context.Context contract HOT 3
- [Suggestions] Introducing an AI-powered robot to assist with daily issue and pull request (PR) tasks.
- Need c.JSON() response like behaviour for c.SSEvent() response for supporting first party clients like OpenAI SDK HOT 2
- custom time.Time type can not use bindQuery get a value. HOT 2
- configure server parameters HOT 1
- The binding:"required" tag does not seem to work for struct types HOT 3
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.