2 回答

TA貢獻1853條經驗 獲得超18個贊
我們是否需要在使用 c.ShouldBindJSON 之前顯式處理解壓縮?
當然。GinShouldBindJSON
不知道您的有效負載可能會或可能不會被編碼。正如方法名稱所暗示的那樣,它需要 JSON 輸入。
如果你想編寫可重用的代碼,你可以實現這個Binding
接口。
一個非常小的例子:
type GzipJSONBinding struct {
}
func (b *GzipJSONBinding) Name() string {
return "gzipjson"
}
func (b *GzipJSONBinding) Bind(req *http.Request, dst interface{}) error {
r, err := gzip.NewReader(req.Body)
if err != nil {
return err
}
raw, err := io.ReadAll(r)
if err != nil {
return err
}
return json.Unmarshal(raw, dst)
}
然后可用于c.ShouldBindWith,它允許使用任意綁定引擎:
err := c.ShouldBindWith(&postData, &GzipJSONBinding{})

TA貢獻1862條經驗 獲得超6個贊
打開的完整工作示例Content-Encoding
curl 嘗試使用它
$ echo '{"data" : "hello"}' | gzip | curl -X POST -H "Content-Type: application/json" -H "Content-Encoding: gzip" --data-binary @- localhost:8080/json
hello
$ curl -X POST -H "Content-Type: application/json" --data-raw '{"data" : "hello"}' localhost:8080/json
hello
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"io"
"log"
"net/http"
)
type PostData struct {
Data string `binding:"required" json:"data"`
}
func main() {
r := gin.Default()
r.POST("/json", func(c *gin.Context) {
var postdata PostData
contentEncodingHeader := c.GetHeader("Content-Encoding")
switch contentEncodingHeader {
case "gzip":
if err := c.ShouldBindBodyWith(&postdata, gzipJSONBinding{}); err != nil {
log.Println("Error parsing GZIP JSON request body", "error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
case "":
if err := c.ShouldBindJSON(&postdata); err != nil {
log.Println("Error parsing JSON request body", "error", err)
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
default:
log.Println("unsupported Content-Encoding")
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "unsupported Content-Encoding"})
return
}
log.Printf("%s", postdata)
if !c.IsAborted() {
c.String(200, postdata.Data)
}
})
r.Run()
}
type gzipJSONBinding struct{}
func (gzipJSONBinding) Name() string {
return "gzipjson"
}
func (gzipJSONBinding) Bind(req *http.Request, obj interface{}) error {
if req == nil || req.Body == nil {
return fmt.Errorf("invalid request")
}
r, err := gzip.NewReader(req.Body)
if err != nil {
return err
}
raw, err := io.ReadAll(r)
if err != nil {
return err
}
return json.Unmarshal(raw, obj)
}
func (gzipJSONBinding) BindBody(body []byte, obj interface{}) error {
r, err := gzip.NewReader(bytes.NewReader(body))
if err != nil {
return err
}
return decodeJSON(r, obj)
}
func decodeJSON(r io.Reader, obj interface{}) error {
decoder := json.NewDecoder(r)
if err := decoder.Decode(obj); err != nil {
return err
}
return validate(obj)
}
func validate(obj interface{}) error {
if binding.Validator == nil {
return nil
}
return binding.Validator.ValidateStruct(obj)
}
- 2 回答
- 0 關注
- 145 瀏覽
添加回答
舉報