亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在綁定之前顯式處理壓縮的 json

在綁定之前顯式處理壓縮的 json

Go
慕斯709654 2022-10-10 19:22:41
我想編寫一個 api,它將通過 POST 發送 gzip 壓縮的 json 數據。雖然下面可以處理正文中的簡單 json,但如果 json 被壓縮,則不處理。使用前是否需要明確處理解壓c.ShouldBindJSON?如何重現package mainimport (    "github.com/gin-gonic/gin"    "log"    "net/http")func main() {    r := gin.Default()    r.POST("/postgzip", func(c *gin.Context) {                type PostData struct {            Data string `binding:"required" json:"data"`        }                var postdata PostData        if err := c.ShouldBindJSON(&postdata); err != nil {            log.Println("Error parsing request body", "error", err)            c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})            return        }        log.Printf("%s", postdata)        if !c.IsAborted() {            c.String(200, postdata.Data)        }    })    r.Run()}? echo '{"data" : "hello"}' | curl -X POST -H "Content-Type: application/json" -d @- localhost:8080/postgziphello期望$ echo '{"data" : "hello"}' | gzip | curl -v -i -X POST -H "Content-Type: application/json" -H "Content-Encoding: gzip" --data-binary @- localhost:8080/postgziphello實際結果$ echo '{"data" : "hello"}' | gzip | curl -v -i -X POST -H "Content-Type: application/json" -H "Content-Encoding: gzip" --data-binary @- localhost:8080/postgzip{"error":"invalid character '\\x1f' looking for beginning of value"}環境去版本:go version go1.17.2 darwin/amd64gin 版本(或提交參考):v1.7.4操作系統:MacOS Monterey
查看完整描述

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{})


查看完整回答
反對 回復 2022-10-10
?
阿波羅的戰車

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)

}


查看完整回答
反對 回復 2022-10-10
  • 2 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號