Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
27
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

@harumaxy

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

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--

送信側 : 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: バイナリとして送る

受信側: 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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
27
Help us understand the problem. What are the problem?