当前位置: 代码网 > it编程>前端脚本>Golang > 探索Gin框架:Golang使用Gin完成文件上传

探索Gin框架:Golang使用Gin完成文件上传

2024年07月28日 Golang 我要评论
Go标准库net/http对文件上传已经提供了非常完善的支持,Gin框架在其基础做了封装,使用更加简单便捷。作者:鼠鼠我捏,要死了捏

前言

在之前的文章中,我们讲解了gin框架的快速入门使用,今天我们来聊聊如何使用gin实现文件上传。

go标准库net/http对文件上传已经提供了非常完善的支持,而gin框架在其基础上进一步封装,因此使用gin开发文件上传功能时,只需要简单几行代码便可以实现,gin框架支持单个文件与多个文件同时上传。

目录

​编辑

前言

使用原生net/http库实现文件上传

使用gin实现文件上传

单个文件上传

formfile()获取文件

saveuploadedfile()保存到本地 

设置缓冲区大小

限制文件大小

限制文件类型

完整示例

测试文件上传

多个文件上传

multipartform()获取多个文件

测试文件上传

总结


使用原生net/http库实现文件上传

我们首先看看实现一个http服务器,提供文件上传功能的简单示例

package main

import (
    "io"
    "io/ioutil"
    "log"
    "net/http"

    "github.com/julienschmidt/httprouter"
)

const (
    max_upload_size = 1024 * 1024 * 20 //最大上传大小,50mb
)

func main() {
    r := registerhandlers()

    http.listenandserve(":8080", r)  // 开启一个http服务
}

// 定义路由
func registerhandlers() *httprouter.router {
    router := httprouter.new()

    router.post("/upload", uploadhandler)

    return router
}
// 文件上传接口
func uploadhandler(w http.responsewriter, r *http.request, p httprouter.params) {
    r.body = http.maxbytesreader(w, r.body, max_upload_size)
    if err := r.parsemultipartform(max_upload_size); err != nil {
        log.printf("file is too big")
        return
    }
    file, headers, err := r.formfile("file")
    if err != nil {
        log.printf("error when try to get file: %v", err)
        return
    }
    //获取上传文件的类型
    if headers.header.get("content-type") != "image/png" {
        log.printf("只允许上传png图片")
        return
    }
    data, err := ioutil.readall(file)
    if err != nil {
        log.printf("read file error: %v", err)
        return
    }
    fn := headers.filename
    err = ioutil.writefile("./video/"+fn, data, 0666)
    if err != nil {
        log.printf("write file error: %v", err)
        return
    }
    w.writeheader(http.statuscreated)
    io.writestring(w, "uploaded successfully")
}

如上我们通过r.formfile函数获取上传的文件对象,以及文件的相关信息。然后通过headers.header.get函数获取上传文件的类型,判断类型是否符合要求。接着,使用ioutil.readall函数读取文件的内容,并将其存储在data变量中。然后,通过headers.filename获取上传文件的文件名,并使用ioutil.writefile函数将文件内容写入到指定路径下的文件中。

使用gin实现文件上传

单个文件上传

formfile()获取文件

单文件上传使用gin.contextformfile()方法,该方法的值为post请求中文件上传字段的名称:

 engine := gin.default()
 engine.post("/upload", func(c *gin.context) {
     file, err := c.formfile("file")
 })
 engine.run()

saveuploadedfile()保存到本地 

调用gin.contextsaveuploadedfile()方法可以将文件保存到某个目录下:

 dst := "./uploads/" + file.filename
 c.saveuploadedfile(file,"./uploadfile")

设置缓冲区大小

go默认文件上传缓冲区为32m,当有大量文件上传时,服务器内存的压力会很大,因此可以通过maxmultipartmemory属性来设置缓冲区大小:

 //8m
 engine.maxmultipartmemory = 8 << 20

限制文件大小

上传文件时,不限制文件大小可以会导致服务存储空间暴涨,因为有必须限制上传文件大小:

 filemaxsize := 4 << 20 //4m
 if int(file.size) > filemaxsize {
   c.string(http.statusbadrequest, "文件不允许大小于4m")
   return
 }

限制文件类型

对文件类型,也可以进行限制:

 reader, err := file.open()
 if err != nil {
   fmt.println(err)
   return
 }
 b := make([]byte, 512)
 reader.read(b)
 ​
 contenttype := http.detectcontenttype(b)
 if contenttype != "image/jpeg" && contenttype != "image/png" {
   c.string(http.statusok, "文件格式错误")
   return
 }

在上面的代码中,我们读取文件的前512个字节,再调用http.detectcontenttype()便可以获取文件的mime值。

完整示例

 package main
 ​
 import (
   "fmt"
   "log"
   "net/http"
 ​
   "github.com/gin-gonic/gin"
 )
 ​
 func main() {
   engine := gin.default()
   //8m
   engine.maxmultipartmemory = 8 << 20
   engine.post("/upload", func(c *gin.context) {
     file, err := c.formfile("file")
     if err != nil {
       log.println(err)
       c.string(http.statusbadrequest, "文件上传失败")
       return
     }
     filemaxsize := 4 << 20 //4m
     if int(file.size) > filemaxsize {
       c.string(http.statusbadrequest, "文件不允许大小于32kb")
       return
     }
 ​
     reader, err := file.open()
     if err != nil {
       fmt.println(err)
       return
     }
     b := make([]byte, 512)
     reader.read(b)
 ​
     contenttype := http.detectcontenttype(b)
     if contenttype != "image/jpeg" && contenttype != "image/png" {
       c.string(http.statusok, "文件格式错误")
       return
     }
 ​
     dst := "./uploads/" + file.filename
     c.saveuploadedfile(file, dst)
     c.string(http.statusok, fmt.sprintf("'%s' 上传成功!", file.filename))
   })
   engine.run()
 }
 ​

测试文件上传

$ curl -f "file=@./1.jpg" -x post "http://localhost:8080/upload"
 '1.jpg' 上传成功!

多个文件上传

multipartform()获取多个文件

如果要上传多个文件,多次调用gin.contextformfile()方法也是可以的,但更好的方式是使用gin.contextmultipartform()方法:

 package main
 ​
 import (
   "fmt"
   "log"
   "net/http"
 ​
   "github.com/gin-gonic/gin"
 )
 ​
 func main() {
   engine := gin.default()
   engine.post("/uploadmul", func(c *gin.context) {
     form, err := c.multipartform()
     if err != nil {
       log.println(err)
       c.string(http.statusbadrequest, "文件上传失败")
       return
     }
     files := form.file["upload"]
     for _, file := range files {
       fmt.println(file.filename)
     }
     c.string(http.statusok, fmt.sprintf("%d files uploaded!", len(files)))
   })
   engine.run()
 }

测试文件上传

运行程序后,使用curl命令上传多个文件:

$ curl -f "upload=@./1.jpg" -f "upload=@./2.jpg" -x post "http://localhost:8080/uploadmul
2 files uploaded

总结

go标准库net/http对文件上传已经提供了非常完善的支持,可以满足我们大部分需求,gin框架在其基础做了封装,让我们使用起来更加方便迅速。

感谢阅读~

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com