教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang 上传文件(包括 gin 实现)

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

发布时间:2022-03-13   编辑:jiaochengji.com
教程集为您提供golang 上传文件(包括 gin 实现)等资源,欢迎您收藏本站,我们将为您提供最新的golang 上传文件(包括 gin 实现)资源

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

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

<h1 id="上传文件">上传文件</h1> <h3 id="标准包实现">标准包实现</h3> <pre><code class="language-go">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 } } </code></pre> <h3 id="gin-实现">Gin 实现</h3> <pre><code class="language-go">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 } } </code></pre>

SaveUploadedFile 实现如下:

<pre><code class="language-go">// 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 } </code></pre> <h1 id="上传文件和参数">上传文件和参数</h1>

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

<h3 id="标准包实现-1">标准包实现</h3>

可以使用 <code>Request</code>下的 MultipartForm

<h4 id="文件参数">文件参数</h4> <pre><code class="language-go">files :=r.MultipartForm.File </code></pre>

files 是 <code>map[string][]*FileHeader</code> 类型, 可以传递多个文件

<h4 id="值参数">值参数</h4> <pre><code class="language-go">values := r.MultipartForm.Value </code></pre>

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

<h3 id="gin-实现-1">Gin 实现</h3>

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

<pre><code class="language-go">type newForm struct { UploadKey *multipart.FileHeader `form:"upload-key"` Name string `form:"name"` Age int `form:"age"` } </code></pre>

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

<pre><code class="language-go"> var form newForm if err := c.ShouldBind(&form); err != nil{ //ignore } </code></pre>

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

<h1 id="multipart-client实现">Multipart client实现</h1>

multipart form 的 client 写法示例

<pre><code class="language-go">package main import ( "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 } </code></pre> <h1 id="总结">总结</h1>

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

<h1 id="参考">参考</h1>

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

到此这篇关于“golang 上传文件(包括 gin 实现)”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Gin 框架绑定 JSON 参数使用 jsoniter
使用 golang的gin框架实现,文件上传
golang 上传文件(包括 gin 实现)
Golang Gin 实战(六)| 获取Form表单参数和原理分析
想系统学习GO语言(Golang
Golang pprof 性能分析与火焰图
gin的一个标准化返回工具
JWT 在 Gin 中的使用
项目结构设置
gin-vue-admin 使用 go mod , golang开发工具 提示package gin-vue-admin/core is not in GOROOT

[关闭]
~ ~