Golang HTTPファイルアップロード
3960 ワード
まず、サーバー側で二つのルートを設定して、ファイルのアップロードに使います。/files/*はファイルのダウンロードに使います。
今はuploadFileHanderを実現するだけです。この処理手順には以下の機能が含まれます。
·ファイルの最大値を検証します。
·要求からファイルとPOSTパラメータを検証する
·提供されたファイルの種類を確認します。
·ランダムファイル名を作成
·ファイルをハードディスクに書き込みます。
·すべてのエラーを処理して、うまくいけば成功メッセージに戻ります。
第一歩は、処理手順を定義します。
幸いにも、Go標準ライブラリは私たちにHttp.DetectContectType関数を提供しています。この関数はmimesniffアルゴリズムに基づいています。ファイルを読み込む512バイトが必要であれば、ファイルの種類を判断することができます。
すべての部分が大丈夫なら、私達はユーザーにi額SUCCESS情報を返します。
参考:
https://www.yuque.com/docs/share/b5d6f032-9f65-48b4-b0fb-87a05bc72672
const maxUploadSize = 2 * 1024 * 2014 // 2 MB
const uploadPath = "./tmp"
func main() {
http.HandleFunc("/upload", uploadFileHandler())
fs := http.FileServer(http.Dir(uploadPath))
http.Handle("/files/", http.StripPrefix("/files", fs))
log.Print("Server started on localhost:8080, use /upload for uploading files and /files/{fileName} for downloading files.")
log.Fatal(http.ListenAndServe(":8080", nil))
}
アップロードするターゲットディレクトリと、私たちが受ける最大ファイルサイズを定数として定義します。ここで注意してください。ファイルサービス全体の概念はこのように簡単です。私たちは標準ライブラリのツールだけを使って、http.FileServerを使ってHTTP処理プログラムを作成します。http.Dir(uplloadPath)が提供するディレクトリを使ってファイルをアップロードします。今はuploadFileHanderを実現するだけです。この処理手順には以下の機能が含まれます。
·ファイルの最大値を検証します。
·要求からファイルとPOSTパラメータを検証する
·提供されたファイルの種類を確認します。
·ランダムファイル名を作成
·ファイルをハードディスクに書き込みます。
·すべてのエラーを処理して、うまくいけば成功メッセージに戻ります。
第一歩は、処理手順を定義します。
func uploadFileHandler() http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
その後、http.MaxBytes Readerを使ってファイルサイズを検証します。ファイルサイズが設定値より大きい場合、エラーを返します。エラーは、エラー情報と対応するHTTP状態コードを返すヘルパープログラムrender Errerによって処理されます。r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
if err := r.ParseMultipartForm(maxUploadSize); err != nil {
renderError(w, "FILE_TOO_BIG", http.StatusBadRequest)
return
}
ファイルサイズの検証が通れば、フォームパラメータの種類とアップロードされたファイルを確認して解析し、ファイルを読みます。この例では、Wieldを明確にするために、派手なio.Readerとio.Writerインターフェースを使用しません。簡単にファイルをバイト配列に読み込むだけです。これは後で書きます。fileType := r.PostFormValue("type")
file, _, err := r.FormFile("uploadFile")
if err != nil {
renderError(w, "INVALID_FILE", http.StatusBadRequest)
return
}
defer file.Close()
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
renderError(w, "INVALID_FILE", http.StatusBadRequest)
return
}
ファイルのサイズを確認し、ファイルを読み込みました。次はファイルの種類を確認します。安いですが、安全ではない方法で、ファイルの拡張子だけを確認して、ユーザーがそれを変えていないと信じていますが、正式なプロジェクトに対してはそうすべきではありません。幸いにも、Go標準ライブラリは私たちにHttp.DetectContectType関数を提供しています。この関数はmimesniffアルゴリズムに基づいています。ファイルを読み込む512バイトが必要であれば、ファイルの種類を判断することができます。
iletype := http.DetectContentType(fileBytes)
if filetype != "image/jpeg" && filetype != "image/jpg" &&
filetype != "image/gif" && filetype != "image/png" &&
filetype != "application/pdf" {
renderError(w, "INVALID_FILE_TYPE", http.StatusBadRequest)
return
}
実際のアプリケーションでは、ファイルメタデータを使用して、データベースに保存したり、外部サービスにプッシュしたりすることがあります。メタデータを解析して操作します。ここではランダムな新しい名前を作成し、新しいファイル名を記録します。fileName := randToken(12)
fileEndings, err := mime.ExtensionsByType(fileType)
if err != nil {
renderError(w, "CANT_READ_FILE_TYPE", http.StatusInternalServerError)
return
}
newPath := filepath.Join(uploadPath, fileName+fileEndings[0])
fmt.Printf("FileType: %s, File: %s
", fileType, newPath)
すぐに完成しました。重要なステップだけが残っています。書類を書きます。上記で提供したように、私たちは読み込んだバイナリファイルを新たに作成したnewFileというファイル処理プログラムにコピーするだけです。すべての部分が大丈夫なら、私達はユーザーにi額SUCCESS情報を返します。
newFile, err := os.Create(newPath)
if err != nil {
renderError(w, "CANT_WRITE_FILE", http.StatusInternalServerError)
return
}
defer newFile.Close()
if _, err := newFile.Write(fileBytes); err != nil {
renderError(w, "CANT_WRITE_FILE", http.StatusInternalServerError)
return
}
w.Write([]byte("SUCCESS"))
これでいいです。この簡単な例をテストして、仮想ファイルを使ってHTMLページをアップロードしてもいいです。参考:
https://www.yuque.com/docs/share/b5d6f032-9f65-48b4-b0fb-87a05bc72672