golang 上传文件(包括 gin 实现)

golang 上传文件(包括 gin 实现),第1张

概述golang web服务有时候需要提供上传文件的接口,以下就是具体示例。为了示例简单(吐槽下 golang 的错误处理), 忽略了所有的错误处理。本文会用两种方式(标准库和gin)详细讲解 golang 实现文件上传的实现。 gin是一个用 golang 实现的优秀 web 服务框架 上传文件 标准包实现 package mainimport ( "io" "log"

golang web服务有时候需要提供上传文件的接口,以下就是具体示例。为了示例简单(吐槽下 golang 的错误处理),忽略了所有的错误处理。本文会用两种方式(标准库和gin)详细讲解 golang 实现文件上传的实现。

gin是一个用 golang 实现的优秀 web 服务框架

上传文件 标准包实现
package mainimport (    "io"    "log"    "net/http"    "os")var (  // 文件 key    uploadfileKey = "upload-key")func main() {    http.HandleFunc("/upload",uploadHandler)    if err := http.ListenAndServe(":8080",nil); err != nil {        log.Fatalf("error to start http server:%s",err.Error())    }}func uploadHandler(w http.ResponseWriter,r *http.Request) {    // 接受文件    file,header,err := r.Formfile(uploadfileKey)    if err != nil {        // ignore the error handler    }    log.Printf("selected file name is %s",header.filename)    // 将文件拷贝到指定路径下,或者其他文件 *** 作    dst,err := os.Create(header.filename)    if err != nil {        // ignore    }    _,err = io.copy(dst,file)    if err != nil {        // ignore    }}
Gin 实现
package mainimport (    "github.com/gin-gonic/gin")var (    uploadfileKey = "upload-key")func main() {    r := gin.Default()    r.POST("/upload",uploadHandler)    r.Run()}func uploadHandler(c *gin.Context) {    header,err := c.Formfile(uploadfileKey)    if err != nil {        //ignore    }    dst := header.filename  // gin 简单做了封装,拷贝了文件流    if err := c.SaveUploadedfile(header,dst); err != nil {        // ignore    }}

SaveUploadedfile 实现如下:

// SaveUploadedfile uploads the form file to specific dst.func (c *Context) SaveUploadedfile(file *multipart.fileheader,dst string) error {    src,err := file.open()    if err != nil {        return err    }    defer src.Close()    //创建 dst 文件    out,err := os.Create(dst)    if err != nil {        return err    }    defer out.Close()// 拷贝文件    _,err = io.copy(out,src)    return err}
上传文件和参数

有时候除了选中文件外,我们还需要向服务端传递一些参数。在 http multipart 请求格式中。值是以键值对的形式传递的。

标准包实现

可以使用 Request下的 MultipartForm

文件参数
files :=r.MultipartForm.file

files 是 map[string][]*fileheader 类型,可以传递多个文件

值参数
values := r.MultipartForm.Value

values 是 map[string][]string 类型,可以允许有多个同名的变量,每个同名的变量值在一个切片中

Gin 实现

ginContext中包含了*http.Request,因此完全可以用与标准库相同的方式处理。同时 gin对参数的获取也做了一层分装。
假设需要传递 name,age 以及 key 为 upload-key 的文件。首先定义结构体:

type newForm struct {    UploadKey *multipart.fileheader `form:"upload-key"`    name      string                `form:"name"`    Age       int                   `form:"age"`}

在获取 form 的时候直接使用 gin分装的方法ShouldBind获取到所有参数

var form newForm    if err := c.ShouldBind(&form); err != nil{        //ignore    }

同时newForm中可以添加binding tag 进行参数校验。具体可以参考 gin 的官方文档 gin 请求参数校验。

Multipart clIEnt实现

multipart form 的 clIEnt 写法示例

package mainimport (    "bytes"    "fmt"    "io"    "log"    "mime/multipart"    "net/http"    "os"    "path/filepath")var (    uploadfileKey = "upload-key")func main() {    url := "http://127.0.0.1:8080/upload"    path := "/tmp/test.txt"    params := map[string]string{        "key1": "val1",}    req,err := NewfileUploadRequest(url,path,params)    if err != nil {        fmt.Printf("error to new upload file request:%s\n",err.Error())        return    }    clIEnt := &http.ClIEnt{}    resp,err := clIEnt.Do(req)    if err != nil {        fmt.Printf("error to request to the server:%s\n",err.Error())        return    }    body := &bytes.Buffer{}    _,err = body.ReadFrom(resp.Body)    if err != nil {        log.Fatal(err)    }    defer resp.Body.Close()    fmt.Println(body)}// NewfileUploadRequest ...func NewfileUploadRequest(url,path string,params map[string]string) (*http.Request,error) {    file,err := os.Open(path)    if err != nil {        return nil,err    }    defer file.Close()    body := &bytes.Buffer{}    // 文件写入 body    writer := multipart.NewWriter(body)    part,err := writer.CreateFormfile(uploadfileKey,filepath.Base(path))    if err != nil {        return nil,err    }    _,err = io.copy(part,file)    // 其他参数列表写入 body    for k,v := range params {        if err := writer.WriteFIEld(k,v); err != nil {            return nil,err        }    }    if err := writer.Close(); err != nil {        return nil,err    }    req,err := http.NewRequest(http.MethodPost,url,body)    if err != nil {        return nil,err    }    req.header.Add("Content-Type",writer.FormDataContentType())    return req,err}
总结

Gin 的实现方式更加简单高效,框架为我们封装了很多细节。使用起来更加方便。标准库实现相对而言也算简单。但是需要我们自己组织和校验请求参数。

参考

gin
https://gist.github.com/mattetti/5914158

总结

以上是内存溢出为你收集整理的golang 上传文件(包括 gin 实现)全部内容,希望文章能够帮你解决golang 上传文件(包括 gin 实现)所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1264824.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存