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
- コンポーネント内で、 React.createRef() ref を作る
- <input type="file" ref={}> のrefに、作成したrefを入れる
- 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
- 【React】axiosを使用してmultipart/form-data形式の通信をする
http://reiji1020.hatenablog.com/entry/2018/12/31/ - React公式 : 非制御コンポーネント
https://ja.reactjs.org/docs/uncontrolled-components.html#the-file-input-tag
Qiita
- WebAPI でファイルをアップロードする方法アレコレ
https://qiita.com/mserizawa/items/7f1b9e5077fd3a9d336b - Goでmultipart/form-dataをparseする
https://qiita.com/r9y9/items/35a1cf139332a3072fc8 - <input type="file">で同じファイルを選択してもchangeイベントをトリガーさせる
https://qiita.com/_Keitaro_/items/57b1c5dd36b7bed08ad8