GinでBodyを取得する際の最大サイズについて


概要

ginで不確定なjosnをinterfaceに変換する際、一定サイズを超えると変換できない状態になった。

コード

func SAmple(c *gin.Context) {
    ~~~
    //bodyを取得
    buf := make([]byte, 1028)
    n, _ := c.Request.Body.Read(buf)
    body := string(buf[0:n])
    //bodyをmapに変換
    var json_parse map[string]interface{}
    err := json.Unmarshal([]byte(b), &json_parse)
    ~~~
}

c.Request.Body.Readでバイトスライスにボディを格納してstring形に変換していますが、
jsonのサイズが一定値を超えるとパースできなくなりました。

私の環境ではnが2575で上限になりそれ以降のリクエストボディがbodyに格納されずjson.Unmarssamlでエラーになっていました。

修正前に

Webサーバがbodyを制限なく受け入れるとbodyサイズだけサーバのメモリが消費されるため、
大きなbodyを送信しサーバをダウンさせるセキュリティホールになります。
そのため、API側で受け取れるbodyに上限を設けることは、Webに公開するAPIの場合必須になります。

その点は注意したうえで実装してください。

修正後

func SAmple(c *gin.Context) {
    ~~~
    //bodyを取得
    var bodyBytes []byte
    if c.Request.Body != nil {
      bodyBytes, _ = ioutil.ReadAll(c.Request.Body)
    }
    c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
    bodyString := string(bodyBytes)
    //変換
    var json_parse map[string]interface{}
    err := json.Unmarshal([]byte(b), &json_parse)
    ~~~
}

ioutil.ReadAllですべてのbodyを読み込めるので問題なくjsonをinterfaceへ変換できます。

まとめ

c.Request.Body.Read(buf)にはサイズに上限がある。
全部読み込みたい場合は、ioutil.ReadAll(c.Request.Body)で読み込みましょう

ありがとうございました。