Help us understand the problem. What is going on with this article?

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 (GoのWebFrameWork)

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 do not you register as a user and use Qiita more conveniently?
  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
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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