Golang Multipart File Upload Example

2023-05-16

http://matt.aimonetti.net/posts/2013/07/01/golang-multipart-file-upload-example/


The Go language is one of my favorite programming languages. However, sometimes doing simple things can seem a bit harder than it should. However, most of the time, the problem is just to find out how to do things the easy way. While Go’s documention isn’t bad, the real key to finding out how to do things is often to look at the source code and the test suite.

I’m not yet super familiar with all the std lib packages, so when I wanted to test my Go web services, I wrote a few lines of code to create a multipart file upload function that was building the body from scratch. Once I was done messing with the various headers, boundary protocol etc.. I started testing some edge cases, I found some bugs in my code. Looking at Go’s packages, I realized that all the tools were already available for me to use. I was just lacking a good example. Walking through the test suite I finally figured out how to write a simple multipart file upload example with some extra query params.

Hopefully this example will be helpful to some of you.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  
package main

import (
  "bytes"
  "fmt"
  "io"
  "log"
  "mime/multipart"
  "net/http"
  "os"
  "path/filepath"
)

// Creates a new file upload http request with optional extra params
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) {
  file, err := os.Open(path)
  if err != nil {
      return nil, err
  }
  defer file.Close()

  body := &bytes.Buffer{}
  writer := multipart.NewWriter(body)
  part, err := writer.CreateFormFile(paramName, filepath.Base(path))
  if err != nil {
      return nil, err
  }
  _, err = io.Copy(part, file)

  for key, val := range params {
      _ = writer.WriteField(key, val)
  }
  err = writer.Close()
  if err != nil {
      return nil, err
  }

  return http.NewRequest("POST", uri, body)
}

func main() {
  path, _ := os.Getwd()
  path += "/test.pdf"
  extraParams := map[string]string{
      "title":       "My Document",
      "author":      "Matt Aimonetti",
      "description": "A document with all the Go programming language secrets",
  }
  request, err := newfileUploadRequest("https://google.com/upload", extraParams, "file", "/tmp/doc.pdf")
  if err != nil {
      log.Fatal(err)
  }
  client := &http.Client{}
  resp, err := client.Do(request)
  if err != nil {
      log.Fatal(err)
  } else {
      body := &bytes.Buffer{}
      _, err := body.ReadFrom(resp.Body)
    if err != nil {
          log.Fatal(err)
      }
    resp.Body.Close()
      fmt.Println(resp.StatusCode)
      fmt.Println(resp.Header)
      fmt.Println(body)
  }
}

Example’s source code on GitHub

All the work is done in the newfileUploadRequest function and really, the mime/multipart package hides all the complexity of creating a multipart request.

The key is to set a new multipart.Writer:


1
  
writer := multipart.NewWriter(body)

The writer will do all the work and will write directly to our body (which itself is a buffer of bytes).

We then create a part for the file form entry with the name of the file param and the name of the file (that we extracted using the path/filepath package). We need to add the content of the file to the file part, we use the io.Copy() to do so. In the first version of this article, I had used io/ioutil Readall to read the content of the file (see code here). However a few readers rightfully mentioned that I should instead copy content from the file to the part instead of temporarily loading the content of the file in memory. Here is an even more optimized version using goroutine to stream the data, and here is the full example using a pipe.


1
2
  
part, _ := writer.CreateFormFile(paramName, filepath.Base(path))
_, err = io.Copy(part, file)

The multipart.Writer takes care of setting the boundary and formating the form data for us, nice isn’t it?!

Then for any extra params passed as a map of string keys to string value, we use another function of themultipart.Writer type:


1
  
writer.WriteField(key, val)

Once again, the writer takes care of creating the right headers, and to add the passed value.

At this point, we just need to close our writer and use our body to create a new request.


1
2
  
writer.Close()
req, _ := http.NewRequest("POST", uri, body)

One last thing before triggering our request, we need to set the header that contains the content type including the boundary being used. Once again, the Go lib has us covered:


1
  
req.Header.Add("Content-Type", writer.FormDataContentType())

As a reference, here is the generated body:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name="file"; filename="doc.pdf"
Content-Type: application/octet-stream

%PDF-1.4
%????
4 0 obj
<</Type /Catalog
// removed for example
trailer
<</Size 18
/Root 4 0 R
>>
startxref
45054
%%EOF
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name="title"

My Document
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name="author"

Matt Aimonetti
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name="description"

A document with all the Go programming language secrets
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee--

Golang might not be as high level as Ruby or Python, but it’s not too far off and it certainly comes with some great std libs. I know I recently caught myself writing a lot of small scripts in Go, something I used to do in Ruby. I think this is mainly due to the fact that Go is compiled, designed for concurrency, has great std libs and is quite easy to write.

Hopefully this code sample illustrates how easy Go can be and can also serve as a reference point if you are looking for a way to do multipart upload.


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Golang Multipart File Upload Example 的相关文章

  • 如何解决:使用 .csv Dictreader 导入文件的 Python 因未定义字符而失败

    首先 我发现下列 https stackoverflow com questions 38019379 python unicodedecodeerror utf8 codec cant decode byte 0x91这与我的问题基本相同
  • 如何打开 matlab p 代码文件

    有谁知道如何查看 matlab p 代码文件的代码 p 代码文件专门存在 以便您可以共享代码 以便其他人无法查看它 换句话说 您看不到 Matlab p 代码文件的代码
  • 在 C# 中创建文件的最快方法

    我正在运行一个程序来测试在包含大量文件的文件夹中查找和迭代所有文件的速度 该过程中最慢的部分是创建超过 100 万个文件 我目前正在使用一种非常幼稚的方法来创建文件 Console Write Creating 0 N0 file s of
  • PHP is_file 和服务器根相对路径

    请问如何使用 is file 和 folder file jpg 这样的路径 谢谢你 如果路径以 开头 则表示该路径是绝对路径 当路径是相对路径时 即不以 开头 则采用相对于 php 脚本的路径 如果您希望 folder file jpg
  • 错误:安装 ffi 时出错:错误:无法构建 gem 本机扩展

    我在 Mac 64 位系统中遇到此错误 并且机器上安装了 xcode Building native extensions This could take a while ERROR Error installing ffi ERROR F
  • Javascript 将 CSV 文件加载到数组中

    我正在 WordPress 中开发一个网页 该网页需要有一个包含所有县的组合框 我有一个 csv 格式的数据集 其中包含所有这些县的约 10k 行 当用户在下拉列表中选择一个县时 我只想在网页中显示所选县的数据 这是我的要求 在 WordP
  • 多线程文件写入

    我正在尝试使用多个线程写入大文件的不同部分 就像分段文件下载器所做的那样 我的问题是 执行此操作的安全方法是什么 我是否打开文件进行写入 创建线程 将 Stream 对象传递给每个线程 我不希望发生错误 因为多个线程可能同时访问同一个对象
  • PHP 一次只能看到 20 个上传文件

    当我尝试一次上传超过 20 个文件时 网络服务器只能看到前 20 个文件 任何其他文件都会被忽略 问题是什么 简单的代码可以尝试
  • C 或 C++ 中是否有轻量级的多部分/表单数据解析器? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在考虑将多部分表单数据解析集成到 Web 服务器模块中 以便可以减轻后端 Web 应用程序 通常用动
  • python 和回文

    我最近写了一个循环的方法 usr share dict words并使用我的返回回文列表ispalindrome x 方法 这是一些代码 有什么问题吗 它只会停止 10 分钟 然后返回文件中所有单词的列表 def reverse a ret
  • Linux shell 命令逐块读取/打印文件

    是否有一个标准的 Linux 命令可以用来逐块读取文件 例如 我有一个大小为 6kB 的文件 我想读取 打印第一个 1kB 然后是第二个 1kB 看来猫 头 尾在这种情况下不起作用 非常感谢 你可以这样做read n在循环中 while r
  • 文件保存在文件系统中 VS 保存在数据库中

    我正在设计一个 servlet 或 Struts2 中的操作 用于文件 图像 文档等 下载 但我想知道哪种更好的方法可以将文件保留在文件系统和数据库中 只需保留文件的路径或将文件保留在数据库中 如 BLOB 我知道当我查询数据库时 哪里的
  • ruby 中的 unshift + file.join

    unshift File join File dirname FILE vendor addressable 2 1 0 lib addressable uri 上面的代码是否访问具有以下路径的文件 vendor addressable 2
  • 移动文件并覆盖[重复]

    这个问题在这里已经有答案了 即使同名文件已存在 我也尝试移动文件 NSFileManager moveItemAtURL location1 toURL location2 Does NSFileManager的方法moveItemAtUR
  • PHP preg_match_all 100 MB 文件

    我读到 preg match all 不是为解析大文件而设计的 但我需要这样做 我增加了 pcre backtrack limit 1000000000 pcre recursion limit 1000000000 我的 PHP memo
  • 上传非常大的文件(>5GB)

    我需要你的帮助 我想用 HTML JQuery 和 PHP 创建一个上传脚本 是否可以编写一个可以上传非常大的文件 gt 5 GB 的脚本 我已经尝试使用 FileReader FormData 和 Blobs 但即使使用这些 我也无法上传
  • 如何使用 JavaScript 上传文件而不进行回发?

    我正在 ASP NET 中进行文件上传 我用了
  • 打开文件路径在 python 中不起作用[重复]

    这个问题在这里已经有答案了 我正在编写一个数据库程序 personica 是我的测试主题 我通常在文件路径的位置有一个变量 但出于测试和演示的目的 我只有一个字符串 在我的计算机上的这个确切位置有一个文本文件 顺便说一句 因为我很偏执 所以
  • C++ 输出到文本文件时换行符[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 这只是一个简单的问题 但我正在尝试将
  • 是否可以使用.NET 跟踪文件操作?

    当以某种方式调用文件操作 例如打开或关闭 时 我是否可以在操作系统继续请求之前处理它 如果可能的话可以通过以下方式取消它 NET http en wikipedia org wiki NET Framework 如果 NET没有这样的能力

随机推荐

  • app后端设计(6)-- LBS

    在LBS的应用中 xff0c 一个基本的需求是查找附近的用户 xff0c 现在有两种做法 xff1a 1 使用mysql的空间数据库 xff0c 具体做法参考 xff1a http blog sina com cn s blog a48af
  • app后端设计--总目录

    做了3年app相关的系统架构 xff0c api设计 xff0c 先后在3个创业公司中工作 xff0c 经历过手机网页端 xff0c android客户端 xff0c iphone客户端 xff0c 现就职于app云后端平台bmob xff
  • app后端设计(7)-- 项目管理

    移动互联网行业是个快速发展的行业 xff0c 需求不断变化 xff0c 产品更新快 基于移动互联网的以上特点 xff0c 在开发产品的过程中 xff0c 我们放弃了传统的瀑布流开发模型 xff0c 引入了精益的理念和scrum 这个敏捷开发
  • app后端设计(8)-- 数据库分表

    当项目上线后 xff0c 随着用户的增长 xff0c 有些数据表的规模会以几何级增长 xff0c 当数据达到一定规模的时候 xff08 例如100万条 xff09 xff0c 查询 xff0c 读取性能就下降得很厉害 xff0c 这时 xf
  • app后端设计(9)-- 动态通知

    在app中 xff0c 例如在通知界面 xff0c 当新通知的时候 xff0c 需要显示有多少条通知 xff0c 用户点击 获取新通知 后 xff0c 就能看到新的通知 那么在app端 xff0c 怎么才能知道有多少条新通知 xff1f 实
  • app后端设计(10)--数据增量更新

    在新浪微博的app中 xff0c 从别的页面进入主页 xff0c 在没有网络的情况下 xff0c 首页中的已经收到的微博还是能显示的 xff0c 这显然是把相关的数据存储在app本地 使用数据的app本地存储 xff0c 能减少网络的流量
  • app后端设计(11)-- 系统架构(2014.12.05更新)

    个人认为 xff0c 在小型的创业团队中 xff0c 特别是以应用产品为主 xff0c 在架构后台的时候 xff0c 需要集中精力解决自身业务上的问题 xff0c 不是花时间解决第三方已经解决的问题 xff0c 简单点来说 xff0c 就是
  • 多机器人集群网络通信协议分析

    本文讨论的是多机器人网络通信各层的情况和协议 每个机器人连接一个数据传输通信模块 xff08 以下简称为数传 xff0c 也泛指市面上的图传或图数一体的通信模块 xff09 xff0c 数传之间进行组网来传递信息 根据ISO的划分 xff0
  • Nginx多虚拟主机下泛域名配置

    http www tuicool com articles F3Azuq 近上一个应用 xff0c 让用户可以自定义二级域名 xff0c 所以要配置一个泛域名来解析用户的自定义域名 首先来说说nginx下的泛域名配置 xff0c nginx
  • PHP集成支付宝快速实现充值功能

    http blog lixiphp com php alipay fast chongzhi axzz2wy4huhBm 本文将介绍如何快速通过PHP类库来集成 整合支付宝来实现充值功能 如果你的系统想要扩充积分 账户余额等功能 xff0c
  • 分布式定时任务框架——python定时任务框架APScheduler扩展

    http bbs 7boo org forum php mod 61 viewthread amp tid 61 14546 如果将定时任务部署在一台服务器上 xff0c 那么这个定时任务就是整个系统的单点 xff0c 这台服务器出现故障的
  • yii批量插入的方法

    code style margin 0px padding 0px border 0px font family none span class kwd style margin 0px padding 0px border 0px spa
  • MongoDB之DBref(关联插入,查询,删除) 实例深入

    http blog csdn net crazyjixiang article details 6668288 suppose I have the following datastructure var user 61 id 39 foo
  • MongoDB基本使用

    http www cnblogs com TankMa archive 2011 06 08 2074947 html 成功启动MongoDB后 xff0c 再打开一个命令行窗口输入mongo xff0c 就可以进行数据库的一些操作 输入h
  • 一个靠谱的phpredisadmin文件

    http download csdn net detail newjueqi 7227487
  • CORS(跨域资源共享) 的配置

    http blog csdn net ohyoyo2014 article details 24863197 兼容情况 xff1a 各种新版本的ie10 firefox opera safari chrome以及移动版safari和andr
  • Go调用C代码,Cgo札记

    http www myexception cn program 679738 html Go调用C代码 xff0c Cgo笔记 参考 xff1a 官方文档 xff1a http golang org cmd cgo http blog go
  • node.js面向对象实现(二)继承

    http blog sina com cn s blog b5a53f2e0101nrdi html 继承是面向对象中非常重要的一个概念 xff0c 那么在Node js中如何实现继承呢 xff1f node js在util中提供了inhe
  • ubuntu20安装electron并用electron-packager打包

    起因是想复现港科大的无人机集群GUI界面 xff1a https github com HKUST Aerial Robotics swarm gcs 这是一个用javascript写的 xff0c 基于electron和nodejs的可以
  • Golang Multipart File Upload Example

    http matt aimonetti net posts 2013 07 01 golang multipart file upload example The Go language is one of my favorite prog