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

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

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

上传文件

标准包实现

package main

import (
    "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 main

import (
    "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 请求参数校验

总结

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

参考

gin

猜你喜欢

转载自www.cnblogs.com/jssyjam/p/11428683.html