go实现Http Server文件服务器,提供上传、下载功能

158次阅读
没有评论

共计 3318 个字符,预计需要花费 9 分钟才能阅读完成。

server.go

package main

import (
  "fmt"
  "io"
  "net/http"
  "net/url"
  "os"
  "strconv"
  "strings"
)

func upload(w http.ResponseWriter, req *http.Request) {
  contentType := req.Header.Get("content-type")
  contentLen := req.ContentLength

  fmt.Printf("upload content-type:%s,content-length:%d", contentType, contentLen)
  if !strings.Contains(contentType, "multipart/form-data") {
    w.Write([]byte("content-type must be multipart/form-data"))
    return
  }
  if contentLen >= 4*1024*1024 { // 10 MB
    w.Write([]byte("file to large,limit 4MB"))
    return
  }

  err := req.ParseMultipartForm(4 * 1024 * 1024)
  if err != nil {
    //http.Error(w, err.Error(), http.StatusInternalServerError)
    w.Write([]byte("ParseMultipartForm error:" + err.Error()))
    return
  }

  if len(req.MultipartForm.File) == 0 {
    w.Write([]byte("not have any file"))
    return
  }

  for name, files := range req.MultipartForm.File {
    fmt.Printf("req.MultipartForm.File,name=%s", name)

    if len(files) != 1 {
      w.Write([]byte("too many files"))
      return
    }
    if name == "" {
      w.Write([]byte("is not FileData"))
      return
    }

    for _, f := range files {
      handle, err := f.Open()
      if err != nil {
        w.Write([]byte(fmt.Sprintf("unknown error,fileName=%s,fileSize=%d,err:%s", f.Filename, f.Size, err.Error())))
        return
      }

      path := "./" + f.Filename
      dst, _ := os.Create(path)
      io.Copy(dst, handle)
      dst.Close()
      fmt.Printf("successful uploaded,fileName=%s,fileSize=%.2f MB,savePath=%s \n", f.Filename, float64(contentLen)/1024/1024, path)

      w.Write([]byte("successful,url=" + url.QueryEscape(f.Filename)))
    }
  }
}

func getContentType(fileName string) (extension, contentType string) {
  arr := strings.Split(fileName, ".")

  // see: https://tool.oschina.net/commons/
  if len(arr) >= 2 {
    extension = arr[len(arr)-1]
    switch extension {
    case "jpeg", "jpe", "jpg":
      contentType = "image/jpeg"
    case "png":
      contentType = "image/png"
    case "gif":
      contentType = "image/gif"
    case "mp4":
      contentType = "video/mpeg4"
    case "mp3":
      contentType = "audio/mp3"
    case "wav":
      contentType = "audio/wav"
    case "pdf":
      contentType = "application/pdf"
    case "doc", "":
      contentType = "application/msword"
    }
  }
  // .*( 二进制流,不知道下载文件类型)
  contentType = "application/octet-stream"
  return
}

func download(w http.ResponseWriter, req *http.Request) {
  if req.RequestURI == "/favicon.ico" {
    return
  }

  fmt.Printf("download url=%s \n", req.RequestURI)

  filename := req.RequestURI[1:]
  enEscapeUrl, err := url.QueryUnescape(filename)
  if err != nil {
    w.Write([]byte(err.Error()))
    return
  }

  f, err := os.Open("./" + enEscapeUrl)
  if err != nil {
    w.Write([]byte(err.Error()))
    return
  }

  info, err := f.Stat()
  if err != nil {
    w.Write([]byte(err.Error()))
    return
  }

  _, contentType := getContentType(filename)
  w.Header().Set("Content-Disposition", "attachment; filename="+filename)
  //w.Header().Set("Content-Type", http.DetectContentType(fileHeader))
  w.Header().Set("Content-Type", contentType)
  w.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))

  f.Seek(0, 0)
  io.Copy(w, f)
}

func main() {
  fmt.Printf("linsten on :8080 \n")
  http.HandleFunc("/file/upload", upload)
  http.HandleFunc("/", download)
  http.ListenAndServe(":8080", nil)
}

上传:使用postman测试
输入URL,切换为post
Headers里面增加
key: Content-Type
value: multipart/form-data

Body里面增加
key: file
values: #点击选择文件

点击send即可
linsten on :8080
upload content-type:multipart/form-data; boundary=————————–426273861938235320783216,content-length:379127req.MultipartForm.File,name=filesuccessful uploaded,fileName=头像.jpg,fileSize=0.36 MB,savePath=./头像.jpg
download url=/%E5%A4%B4%E5%83%8F.jpg

下载测试
直接在浏览器输入:
http://10.0.106.117:8080/%E5%A4%B4%E5%83%8F.jpg

注意:
需要对url进行编码,go代码如下:

// 编码 -> %E5%A4%B4%E5%83%8F.jpg
fileName := url.QueryEscape(“头像.jpg”)

// 解码 -> 头像.jpg
enEscapeUrl, err := url.QueryUnescape(fileName)

正文完
 
admin
版权声明:本站原创文章,由 admin 2022-10-15发表,共计3318字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码