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.

Golang Multipart File Upload Example的更多相关文章

  1. jQuery File Upload 单页面多实例的实现

    jQuery File Upload 的 GitHub 地址:https://github.com/blueimp/jQuery-File-Upload 插件描述:jQuery File Upload ...

  2. 【转发】Html5 File Upload with Progress

    Html5 File Upload with Progress               Posted by Shiv Kumar on 25th September, 2010Senior Sof ...

  3. 《Play for Java》学习笔记(六)文件上传file upload

    一. Play中标准方法 使用表单form和multipart/form-data的content-type类型. 1.Form @form(action = routes.Application.u ...

  4. jQuery File Upload

    jQuery File Upload介绍.............................................. 2 实现基本原理......................... ...

  5. jQuery File Upload blueimp with struts2 简单试用

    Official Site的话随便搜索就可以去了 另外新版PHP似乎都有问题  虽然图片都可以上传  但是response报错  我下载的是8.8.7木有问题   但是8.8.7版本结合修改main. ...

  6. html5 file upload and form data by ajax

    html5 file upload and form data by ajax 最近接了一个小活,在短时间内实现一个活动报名页面,其中遇到了文件上传. 我预期的效果是一次ajax post请求,然后在 ...

  7. Angular2 File Upload

    Angular2 File Upload Install Install the components npm install ng2-file-upload --save github: https ...

  8. [EXP]Adobe ColdFusion 2018 - Arbitrary File Upload

    # Exploit Title: Unrestricted # Google Dork: ext:cfm # Date: -- # Exploit Author: Pete Freitag of Fo ...

  9. 【DVWA】Web漏洞实战之File Upload

    File Upload File Upload,即文件上传漏洞,一般的上传漏洞可能是未验证上传后缀 或者是验证上传后缀被bypass 或者是上传的文件验证了上传后缀但是文件名不重命名. LOW 直接上 ...

随机推荐

  1. 在GitHub上创建代码仓库

    目前在GitHub上管理托管带代码的人越来越多了,今天也尝试了一次,顺便记下来,备用. 首先是在GitHub上创建一个代码仓库,创建完之后,GitHub上会有提示,这时进入项目目录执行下面的命令,顺便 ...

  2. 复位windows网络参数的方法

    使用电脑的时候,经常会遇到网络相关的问题,以前读大学的时候就知道怎么解决,就是下面这个方案. 开始-全部程序-附件-命令提示符-右键-以管理员身份运行出来一个黑底白字的窗口,在里面输入: netsh ...

  3. GNU中的处理目标文件的若干工具

    AR 创建静态库,插入.删除.列出和提取成员: SRING 列出目标文件中的字符串: SIRIP 从目标文件中删除符号表信息: NM 列出目标文件符号表中定义的符号: SIZE 列出目标文件中节的名字 ...

  4. Course2-Python函数和模块

    一. 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率. 上一课里提到了Python的很多内置函数.在此主要讲自定义函数. 1. 定 ...

  5. add two numbers(将两个链表相加)

    You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...

  6. 我对IoC/DI的理解

    IoC IoC: Inversion of Control,控制反转, 控制权从应用程序转移到框架(如IoC容器),是框架共有特性 1.为什么需要IoC容器 1.1.应用程序主动控制对象的实例化及依赖 ...

  7. TCP / IP,HTTP

    大学学习网络基础的时候老师讲过,网络由下往上分为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层.通过初步的了解,我知道IP协议对应于网络层,TCP协议对应于传输层,而HTTP协议对应于应用 ...

  8. 《MySQL必知必会》读书笔记_2

    通配符:(尾空格可能会干扰通配符匹配) % 匹配任意字符 _ 匹配任意单个字符 正则表达式:REGEXP 用法就是替换掉LIKE的位置,后面配合正则表达式. 默认不区分大小写,如果区分的话添加关键字B ...

  9. 全面解读Java NIO工作原理(1)

    全面解读Java NIO工作原理(1) 2011-12-14 10:31 Rollen Holt Rollen Holt的博客 我要评论(0) 字号:T | T JDK 1.4 中引入的新输入输出 ( ...

  10. Memcache 运行情况

    Memcache Memcache是danga.com的一个开源项目,它是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的Hash表,能够用来存储各种格式的数据. 查看当前的me ...