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

在这里插入图片描述

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

在这里插入图片描述

  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
在这里插入图片描述

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

具体代码在:

server\src\internal\filegw
  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
gohttp是一个http文件服务器,因为是用go语言写的,所以加了一个go的抬头。之所以用go是因为发布起来是一个二进制文件,不同的平台都可以用,而且没有依赖问题,且稳定性也很好。    这个软件从很久以前就开始写了,第一次提交实在2015年的2月11号,作为组内存放公共文件的一个小软件。一开始的功能只有像 python -mSimpleHTTPServer 那种简单的功能。但是当我看到gotty这个软件的时候 ,意思到一个简单的软件竟然可以做到如此出色。之后这个http文件服务器就不断的被优化着,保持着简单易用的同时,开始赋予了它最强大的功能。    这个软件有很多的技术,隐藏在了其简易朴实的外表之下。请容我简单的介绍下pjax简称页面ajax技术        在gohttp进行目录却换的时候,你会看到地址栏在变,但是页面却是局部刷新的。各种文件的预览功能        所有常见的代码都可以直接在gohttp下预览,如果你用的是chrome浏览器的话,包括pdf,mp4,mp3都可以直接预览。实时的目录zip打包下载        强大的体现在它是实时的,即使你马上在目录下新增了一个文件,点击目录zip下载的时候,这个文件也会出现在里面。二维码的支持        手机下载往往没有电脑下载这么容易,点点鼠标就可以了。但是有了二维码,手机也只用扫一扫就可以下载了。苹果应用的在线安装        iphone应用安装包的扩展名是ipa,但是你还必须有个额外的plist文件才行。以及生成一个itms-services开头的地址,gohttp直接把这些工作都做了,ipa的解析,plist以及下载页面的自动生成。同普通文件一样,只需要点击右侧的生成二维码,然后用iphone手机扫描下,iphone的应用就安装到了你的手机上。PS:坑爹的苹果,就不能像安卓一样简单一点吗README文件的自动显示像github网站上的项目,readme文件都会作为项目的介绍自动显示出来。gohttp也借鉴了一下。如果目录下有readme文件的话,就会自动预览出来。文件上传简单的文件上传也有着出色的表现,可以看到上传的进度,以及支持拖拽的方式上传文件。为了更方便的结合自动发布的功能文件上传也有其相应的API,上传的时候也可是指定软件的版本号,存储结构参考了python,pypi官方的模式。还有很多很多其他的特性    http basic auth认证,不同文件不同的icon,gzip支持,目录的整合显示.... 还有很多功能等待着你去发现和有能力的你去补充。    截图  标签:gohttp

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值