Golang 實現文件上傳和下載服務

前言

在開發的過程中,難免會碰到上傳 / 下載文件的場景。如果這個功能服務端沒開發好,就沒法進行測試。

所以每次都要自己先實現一遍,本文使用 go 寫了一個簡單的文件上傳和下載服務。

以後再碰到這種場景的時候就可以快速進行開發。

下載

因爲下載比較簡單, go 語言默認就有,所以先來說一下下載。

熟悉 go 的都知道, go 對文件服務器有默認的支持,所以我們直接調用相關的 API 就能完成對應的操作。

http.Handle("/", http.FileServer(http.Dir("/tmp/Downloads")))
http.ListenAndServe(":8080", nil)

在這裏需要用 http 包中的 FileServer 函數,它需要一個文件夾,我這裏使用的是一個臨時目錄 /tmp/Downloads

接着需要把這個 Handler 綁定到一個路由中,這裏綁定的就是 /

最後需要啓動這個服務,我把這個服務綁定到 8080 端口,然後使用 go run main.go 就可以運行服務器了。

你可以通過 http://localhost:8080/ 來查看 /tmp/Downloads 下所有的文件。

上傳

與下載不同的是, go 沒有提供默認的實現(也許有,我不知道),所以我們需要自己實現。

實現文件上傳也比較簡單

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Receive Upload: ", time.Now())
    file, header, err := r.FormFile("file")
    if err != nil {
        fmt.Println("Failed to get file data ", err.Error())
        _, _ = io.WriteString(w, err.Error())
        return
    }
    defer file.Close()
    newFile, err := os.Create(header.Filename)
    if err != nil {
        fmt.Println("Failed to create file ", err.Error())
        return
    }
    defer newFile.Close()
    _, err = io.Copy(newFile, file)
    if err != nil {
        fmt.Println("Copy ", header.Filename, " to ", newFile.Name()"failed ", err.Error())
        return
    }
    fmt.Println("Upload File Success ", newFile.Name()",", time.Now())
}

func main() {
    http.HandleFunc("/upload", uploadHandler)
    http.ListenAndServe(":8080", nil)
}

我們把上傳的邏輯放到 uploadHandler 這個函數中,並綁定到 /upload 這個路由上。

uploadHandler 中會從表單中讀取 file 的文件,然後用它在本地創建一個同名的文件,接着把內容拷貝到新創建的本地文件中。這樣就完成了。

現在我們就可以使用 curl 來測試一下上傳文件

curl -X POST http://localhost:8080/upload \
  -F "file=@/tmp/upload.go" \
  -H "Content-Type: multipart/form-data"

不出所料,執行完成之後,在當前文件夾下多出了 upload.go 這個文件。

完整代碼

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "time"
)

func uploadHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Receive Upload: ", time.Now())
    file, header, err := r.FormFile("file")
    if err != nil {
        fmt.Println("Failed to get file data ", err.Error())
        _, _ = io.WriteString(w, err.Error())
        return
    }
    defer file.Close()
    newFile, err := os.Create(header.Filename)
    if err != nil {
        fmt.Println("Failed to create file ", err.Error())
        return
    }
    defer newFile.Close()
    _, err = io.Copy(newFile, file)
    if err != nil {
        fmt.Println("copy ", header.Filename, " to ", newFile.Name()"failed ", err.Error())
        return
    }
    fmt.Println("Upload File Success ", newFile.Name()",", time.Now())
}

func main() {
    fmt.Println("Start Go Download Upload Server...")
    http.HandleFunc("/upload", uploadHandler)
    http.Handle("/", http.FileServer(http.Dir("/tmp/Downloads")))
    http.ListenAndServe(":8080", nil)
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/G-lHXl1QIWv7Yvk2Bd1uqg