mirror of
https://github.com/gin-gonic/gin.git
synced 2025-12-13 13:12:17 +08:00
- Add Context.GetRequestBody() method that caches request body bytes - Allows multiple reads of request body without consumption - Integrates with existing ShouldBindBodyWith* caching mechanism - Includes comprehensive tests and usage examples - Addresses issue #1974: Wrap Request.Body for reuse by Gin, middlewares and app code
87 lines
2.2 KiB
Go
87 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func main() {
|
|
r := gin.Default()
|
|
|
|
// Example middleware that reads the request body
|
|
r.Use(func(c *gin.Context) {
|
|
// Get the request body - this can be called multiple times
|
|
body, err := c.GetRequestBody()
|
|
if err != nil {
|
|
c.AbortWithError(http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
// Log the body length for demonstration
|
|
fmt.Printf("Middleware: Request body length: %d bytes\n", len(body))
|
|
|
|
// Store body in context for use by handlers
|
|
c.Set("rawBody", body)
|
|
c.Next()
|
|
})
|
|
|
|
// Handler that also reads the body
|
|
r.POST("/echo", func(c *gin.Context) {
|
|
// Get the body again - this will use the cached version
|
|
body, err := c.GetRequestBody()
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Also get the body that was stored by middleware
|
|
storedBody, exists := c.Get("rawBody")
|
|
if !exists {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "body not found in context"})
|
|
return
|
|
}
|
|
|
|
// Both should be identical
|
|
if string(body) != string(storedBody.([]byte)) {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "bodies don't match"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "Body received and cached successfully",
|
|
"body": string(body),
|
|
"length": len(body),
|
|
})
|
|
})
|
|
|
|
// Handler that uses binding after GetRequestBody
|
|
r.POST("/bind-after-body", func(c *gin.Context) {
|
|
// First bind to a struct - this caches the body
|
|
var jsonData map[string]interface{}
|
|
if err := c.ShouldBindBodyWithJSON(&jsonData); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Then get the raw body - this will use the cached version
|
|
rawBody, err := c.GetRequestBody()
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"raw_body": string(rawBody),
|
|
"parsed_data": jsonData,
|
|
})
|
|
})
|
|
|
|
fmt.Println("Server starting on :9090")
|
|
fmt.Println("Try: curl -X POST -d 'hello world' http://localhost:9090/echo")
|
|
fmt.Println("Or: curl -X POST -H 'Content-Type: application/json' -d '{\"name\":\"test\"}' http://localhost:9090/bind-after-body")
|
|
|
|
r.Run(":9090")
|
|
}
|