ファイルのやりとりなどで使うことが多いmultipart/form-dataですが、今回は、Golnagでmultipart/form-dataを使ってファイルのアップロードを作っていた際に詰まった点について、紹介します。
目次
コンテンツの種類
フロントエンドとバックエンドのデータのやり取りでは、html
、javascript
、png
、json
など様々な種類のデータを扱います。その際にやりとりするデータの種別をMIME Typeを利用して、やり取りするデータ種別を指定します。
multipart/form-dataとは何か
複数の種類のデータを一度に扱える形式です。HTMLフォームなどよく利用されるケースが多いです。また、ファイルアップロードでよく利用されます。下記にフォームの例を示します。
<!--multipart/form-data形式でPOSTする例-->
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="text" name="title" value="Hello"/><br>
<input type="file" name="file"/><br>
<input type="submit" value="SUBMIT"/>
</form>
javascriptでの例は、下記のようにします。$axiosを使っていますが、FormData()を使って、キー、バリュー形式で指定していきます。
const uploadMovie = async () => {
const params = new FormData();
params.append('title', '1111')
// inputで入力したファイルを指定する
params.append('file', fileRef.value)
const res = await $axios.$post('upload', params, {
headers: {
'content-type': 'multipart/form-data',
},
})
console.log(res)
console.log('uploadMovie')
}
サーバサイドの実装例
下記の例は、fileとしてデータをやり取りした場合の例です。
package main
import (
"encoding/base64"
"io"
"log"
"net/http"
"os"
"strings"
)
func main() {
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
file, _, err := r.FormFile("file")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
dst, err := os.Create("data.dat")
if err != nil {
log.Printf("err %v", err)
}
defer dst.Close()
if _, err = io.Copy(dst, file); err != nil {
log.Printf("err %v", err)
}
log.Printf("complite")
})
http.ListenAndServe(":8080", nil)
}
dataURL形式のデータをやり取りする場合
最近では、HTMLにdataURLとしてBase64エンコードしたデータが直接書かれているケースがあります。そのようなケースでは、ファイルに保存せずにデータを直接おくりたいケースもあると思います。そのようなケースでは、下記のようにします。
package main
import (
"encoding/base64"
"io"
"log"
"net/http"
"os"
"strings"
)
const (
defaultMaxMemory = 3200 << 20 // 3200 MB
)
func main() {
http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(defaultMaxMemory)
data := r.FormValue("mp4")
i := strings.Index(data, ",")
dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(data[i+1:]))
dst, err := os.Create("data.dat")
if err != nil {
log.Printf("err %v", err)
}
defer dst.Close()
if _, err = io.Copy(dst, dec); err != nil {
log.Printf("err %v", err)
}
log.Printf("complite")
})
http.ListenAndServe(":8080", nil)
}
ParseMultipartFormで3200MBのデータでも扱えるようにしています。デフォルトでは、32MBが上限となっています。32MB以上のデータやり取りがある場合には、予めサイズを大きくする必要があります。
今回は、ファイルのやり取りなどがある開発でよく利用するmultipart/form-dataについて紹介しました。