LoginSignup
37
32

More than 1 year has passed since last update.

ブラウザからJSでmultipart/form-dataを送信、Ginで受信する

Last updated at Posted at 2019-09-10

Reactでmultipart/form-dataを送信、Ginで受信する

めっちゃ手間取ったのでメモ書き

multipart/form-dataとは

複数のデータを同時に送る形式
RFC2388
https://lemniscus.hatenablog.com/entry/20121027/1351329602

リクエストボディを区切り文字で区切って、複数のデータを送る
例.

引用元 : https://lemniscus.hatenablog.com/entry/20121027/1351329602

-----------------------------174406726119144318502035190680
Content-Disposition: form-data; name="xxxx"

11111
22222
-----------------------------174406726119144318502035190680
Content-Disposition: form-data; name="yyyy"

on
-----------------------------174406726119144318502035190680--

送信側 : Axios (& React.js)

http requestの送信には Axios を使う

送る側は、 FormData オブジェクトを作成して、値をappendして送る
httpリクエストの構成は、

  • application/json (FormData)
    • text/plane (情報のjson string)
    • image/* (画像ファイル)

の3要素となる。

formタグ部分



const [formData, setFormData] = useState({
    title: "",
    author: "",
    description: ""
})
const fileInput = React.createRef()

return(
    <form>
    <input type="text" name="title" value={formData.title} onChange={handleChange}/>
    <input type="text" name="author" value={formData.author} onChange={handleChange}/>
    <input type="text" name="description" value={formData.description} onChange={handleChange}/>
    <input type="file" name="image" ref={fileInput} accept="image/*"/>
    </form>
)

<input type="file"/> のvalueは、ユーザーしか操作できないため
ファイル入力タグは 非制御コンポーネント と呼ばれる。

Reactでは、formの各inputのvalueを state などで制御することを推奨している。
しかし、<input type="file"/> は state で制御せず、参照するだけ。

React公式サイトにて、Reactでファイル送信フォームを作るための解説が載ってる
https://ja.reactjs.org/docs/uncontrolled-components.html#the-file-input-tag

  1. コンポーネント内で、 React.createRef() ref を作る
  2. <input type="file" ref={}> のrefに、作成したrefを入れる
  3. Submitでファイル送信するときは、 ref.current.files[0] を使う

Submit部分


handleSubmit = async (event) => {
        event.preventDefault()
        const submitData = new FormData()

        submitData.append("formData", JSON.stringify(formData))
        submitData.append("image", fileInput.current.files[0])

        await axios.post(`http://api/posts`, submitData,
            {
                headers: {
                'content-type': 'multipart/form-data',
            },
          })
    }

axiosのpostメソッドで送る。
multipart/form-data でデータを送信するには、 FormData() オブジェクトを作り
送信するデータ(string or binary)をFormNameにappendする

  • json : JSON.Stringify()して送る
  • image: バイナリとして送る

受信側: Golang (gin)

multipart/formdata は、バイナリや複数ファイルを送るのに優れるが
jsonフォーマットをパースするwebフレームワークの機能と相性が悪い

image はgin.Context.Request.FormFile("image")でファイル形式で取得できる
ioパッケージを使って、そのままos.Create()したファイルにコピーできる。

jsonはtext/planeで送られるので、 gin.Context.FormValue("formData")でstring値を
取得して、[]byte型にキャストしたあとjson.Unmarshal()する


func(c *gin.Context) {
    // 画像の保存
    image, header, _ := c.Request.FormFile("image")
    saveFile, _ := os.Create("./images/" + header.Filename)
    defer saveFile.Close()
    io.Copy(saveFile, image)

    // json情報の取得
    jsonStr := c.Request.FormValue("formData")
    var p Post
    json.Unmarshal([]byte(jsonStr), &p)
    fmt.Println(p.Title, p.Author, p.Description)

	c.JSON(201, p)
}

参考リンク

RFC2388
https://www.ietf.org/rfc/rfc2388.txt

React

Qiita

37
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
32