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

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测试

  1. 输入URL,切换为post
  2. Headers里面增加
key: Content-Type
value: multipart/form-data

go实现Http Server文件服务器,提供上传、下载功能_第1张图片

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

go实现Http Server文件服务器,提供上传、下载功能_第2张图片

  1. 点击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)

开源分布式对象存储minio推荐

github:https://github.com/minio/minio
starts:20.5 k
go实现Http Server文件服务器,提供上传、下载功能_第3张图片

如果想知道如何使用minio实现自己的文件服务器
请移步:
https://github.com/xmcy0011/CoffeeChat

具体代码在:

server\src\internal\filegw

你可能感兴趣的:(IM开发,Golang学习)