【Golang实现文件服务器】(一)初始版本

在开发Web应用时,文件的上传下载是一个十分常用的功能。基本上每个项目都要重新开发一遍,很啰嗦不说,本身性能也不是很优秀,功能并不强大。

说起来我们自家的应用用的是阿里云的OSS服务,感觉非常好用,于是为了以后省事,决定使用Golang来开发一个基于http的文件服务器,提供类似的服务。

这个服务目前仅仅完成了简单的文件上传和访问功能。计划在未来几个月逐步完善更丰富的功能,诸如文件去重,图片处理,分包分路径等,基本上希望参考oss等云存储服务的功能。

在此期间也经历了很多坑,现记录如下:

  • Http文件上传
  • 静态文件访问
  • Ajax跨域上传
  • Golang交叉编译

下面将依次记录在本次开发中遇到的问题和解决方法。

代码:(其中ftpCommand目录下的ftpBootstrap.go文件是服务启动器,同名文件为linux-x64编译的可执行文件)

Github


Http文件上传

http上传自然是最基本的功能。出于web应用的考量,上传是基于form表单的multipart/form-data形式。

	//获取表单中的文件
	file, handler, err := r.FormFile("file")
	if err != nil {
		var response = UploadResponse{State: -1, Msg: err.Error(), URL: ""}
		response.Send(w)
		return
	}
	//文件扩展名
	fileext := filepath.Ext(handler.Filename)
	//用时间戳做文件名防止重名
	filename := strconv.FormatInt(time.Now().Unix(), 10) + fileext
	//新建文件
	f, _ := os.OpenFile("./upload/"+filename, os.O_CREATE|os.O_WRONLY, 0660)
	//保存文件
	_, err = io.Copy(f, file)
复制代码

看下来,Golang保存文件比起java来说简单得多了。自带提供的io工具十分方便。

上传文件之后需要给一个返回信息。在此使用Json作为返回格式,定义结构体如下:

//UploadResponse 返回消息
type UploadResponse struct {
	State int    `json:"state"`
	URL   string `json:"data"`
	Msg   string `json:"msg"`
}

复制代码

有一点需要注意,Golang对于一些格式约定十分敏感,要将此结构体转换为Json,只有首字母大写的字段才能被转换到json中。一开始没有注意这一点,导致转换出的Json一直为空。纠结了好长时间。而后面的json:"msg"等备注可以指定转换成的字段名。

这样一个结构体最终返回的Json结果如下:

{
  "state": 0,
  "data": "/get/1476696601.png",
  "msg": "success"
}
复制代码

静态文件访问

文件成功上传之后,就是访问的功能了。这里用的是Golang自带的FileServer功能。

http.Handle("/get/", http.FileServer(httpDir))
复制代码

一开始按照这样来写,结果并不好用。经过一番尝试和搜索,结果下面的写法才是正确的:

http.Handle("/get/", http.StripPrefix("/get/", http.FileServer(httpDir)))
复制代码

这里有个http.StripPrefix方法。此方法的功能是减掉指定的路由。比如在此就是将请求开头的"/get/"给减掉。这样FileServer才能正确的通过指定的路径来访问文件。


###Ajax跨域上传

这个说起来是一个前端的问题。 原本的代码中使用Jsonp来实现Ajax跨域请求。但是Jsonp本身是个第三方的约定,而且不支持post请求,无法通过post上传FormData数据。

通过网上的资料,可以使用最新的XHR2来实现跨域访问。十分简单方便,可惜只支持ie10以上,不过不管了呀!这必然是历史的潮流啊!

通过XHR2来实现跨域请求的根本在于新增的几个Header:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

第一个指定允许跨域访问的域名,第二个指定访问的方法,第三个指定了接受的Header。

鉴于目前只有这么一个接口,就先写在了上传文件的接口中。按理来说应该是提取出来统一做处理的。

//w define by w http.ResponseWriter
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers",
		"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
	w.Header().Set("Content-Type", "application/json")
复制代码

最后一个Content-Type也是不可少的,否则浏览器不会将返回数据作为json来处理。

将Access-Control-Allow-Origin指定为*是一件挺危险的事情。这样允许所有域名访问。目前作为测试服务临时如此。在具体应用中应当指定为特定域名。


Golang交叉编译

交叉编译是Golang挺酷炫的一个特性。Golang本身虽然不支持一处编译,处处运行的跨平台方式,但是它的交叉编译真的太方便了。

网上的资料不是很新鲜,很多资料中的方法还需要重新用源码进行编译等等工作。在最新的Golang中,已经完全不需要这些繁琐的步骤,要交叉编译,只要一行命令:

GOOS=linux GOARCH=amd64 go build bootstrap.go
复制代码

其中GOOS指定操作系统,常用的有darwin(macOS),windows和linux,GOARCH是平台,支持amd64,386和arm,但是据说arm的支持还不完善。

另外当目标平台与当前平台一致时,GOARCH参数是可以省略的。

通过交叉编译,就可以在我的Macbook上进行开发,打包成一个可执行文件,扔到Linux服务器上启动,简单快捷。比起java动辄一大堆的配套环境简直不知道高到哪里去了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值