Golang HTTP文件上傳


2018年02月08日 10:07:13  閱讀數:346 標簽: golang HTTP 文件上傳

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/lengyuezuixue/article/details/79277691

   首先,我們在服務器端設定兩個路由,/upload用於文件上傳,/files/*用於文件下載。

  1.  
    const maxUploadSize = 2 * 1024 * 2014 // 2 MB
  2.  
    const uploadPath = "./tmp"
  3.  
     
  4.  
    func main() {
  5.  
    http.HandleFunc( "/upload", uploadFileHandler())
  6.  
     
  7.  
    fs := http.FileServer(http.Dir(uploadPath))
  8.  
    http.Handle( "/files/", http.StripPrefix("/files", fs))
  9.  
     
  10.  
    log.Print( "Server started on localhost:8080, use /upload for uploading files and /files/{fileName} for downloading files.")
  11.  
    log.Fatal(http.ListenAndServe( ":8080", nil))
  12.  
    }
   我們還將要上傳的目標目錄,以及我們接受的最大文件大小定義為常量。注意這里,整個文件服務的概念是如此的簡單--我們僅使用標准庫中的工具,使用http.FileServer創建一個HTTP處理程序,它將使用http.Dir(uploadPath)提供的目錄來上傳文件。

  現在我們只需要實現uploadFileHander.這個處理程序將包含以下功能:

       ·驗證文件最大值;

       ·從請求驗證文件和POST參數

       ·檢查所提供的文件類型

       ·創建一個隨機文件名

       ·將文件寫入硬盤

       ·處理所有錯誤,如果一切順利返回成功消息

   第一步,我們定義處理程序:

  1.  
    func uploadFileHandler() http.HandlerFunc {
  2.  
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   然后,我們使用http.MaxBytesReader驗證文件大小,當文件大小大於設定值時它將返回一個錯誤。錯誤將被一個助手程序renderError進行處理,它返回錯誤信息以及對應的HTTP狀態碼。
  1.  
    r.Body = http.MaxBytesReader(w, r.Body, maxUploadSize)
  2.  
    if err := r.ParseMultipartForm(maxUploadSize); err != nil {
  3.  
    renderError(w, "FILE_TOO_BIG", http.StatusBadRequest)
  4.  
    return
  5.  
    }
   如果文件大小驗證通過,我們將檢查並解析表單參數類型和上傳的文件,並讀取文件。在本例中,wield清晰起見,我們不使用花哨的io.Reader和io.Writer接口,我們只是簡單的將文件讀取到一個字節數組中,這點我們后面會寫到。
  1.  
    fileType := r.PostFormValue( "type")
  2.  
    file, _, err := r.FormFile( "uploadFile")
  3.  
    if err != nil {
  4.  
    renderError(w, "INVALID_FILE", http.StatusBadRequest)
  5.  
    return
  6.  
    }
  7.  
    defer file.Close()
  8.  
    fileBytes, err := ioutil.ReadAll(file)
  9.  
    if err != nil {
  10.  
    renderError(w, "INVALID_FILE", http.StatusBadRequest)
  11.  
    return
  12.  
    }
   現在我們成功的驗證了文件的大小,並讀取了文件,接下來我們該檢驗文件的類型了。一種廉價但是並不安全的方式,只檢查文件擴展名,並相信用戶沒有改變它,但是對於一個正式的項目來說並不應該這么做。

  幸運的是,Go標准庫提供給我們一個Http.DetectConntectType函數,這個函數基於mimesniff算法,祝需要讀取文件的512個字節就能夠判斷文件的類型。

  1.  
    iletype := http.DetectContentType(fileBytes)
  2.  
    if filetype != "image/jpeg" && filetype != "image/jpg" &&
  3.  
    filetype != "image/gif" && filetype != "image/png" &&
  4.  
    filetype != "application/pdf" {
  5.  
    renderError(w, "INVALID_FILE_TYPE", http.StatusBadRequest)
  6.  
    return
  7.  
    }
   在實際應用程序中,我們可能會使用文件元數據做一些事情,例如將其保存到數據庫或將其推送到外部服務--以任何方式,我們將解析和操作元數據。這里我們創建一個隨機的新名字並將新文件名記錄下來。
  1.  
    fileName := randToken( 12)
  2.  
    fileEndings, err := mime.ExtensionsByType(fileType)
  3.  
    if err != nil {
  4.  
    renderError(w, "CANT_READ_FILE_TYPE", http.StatusInternalServerError)
  5.  
    return
  6.  
    }
  7.  
    newPath := filepath.Join(uploadPath, fileName+fileEndings[ 0])
  8.  
    fmt.Printf( "FileType: %s, File: %s\n", fileType, newPath)
   馬上就大功告成了,只剩下一個關鍵步驟-寫文件。如上文提供的,我們只需要復制讀取的二進制文件到新創建的名為newFile的文件處理程序中。

   如果所有部分都沒問題,我們給用戶返回一個i額SUCCESS信息。

  1.  
    newFile, err := os.Create(newPath)
  2.  
    if err != nil {
  3.  
    renderError(w, "CANT_WRITE_FILE", http.StatusInternalServerError)
  4.  
    return
  5.  
    }
  6.  
    defer newFile.Close()
  7.  
    if _, err := newFile.Write(fileBytes); err != nil {
  8.  
    renderError(w, "CANT_WRITE_FILE", http.StatusInternalServerError)
  9.  
    return
  10.  
    }
  11.  
    w.Write([] byte("SUCCESS"))
   這樣就可以了。你可對這個簡單的例子進行測試,使用虛擬的文件上傳HTML頁面,cURL或工具例如postman。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM