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)
}
key: Content-Type
value: multipart/form-data
key: file
values: #点击选择文件
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)
github:https://github.com/minio/minio
starts:20.5 k
如果想知道如何使用minio实现自己的文件服务器。
请移步:
https://github.com/xmcy0011/CoffeeChat
具体代码在:
server\src\internal\filegw