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. Python和shell中Base64编码使用那些事

    做开发第一个接触的编码方式就是Base64,当时是用url来传输一些参数,传输的两端会用Base64来编码和解码,保证数据不被url转义破坏. 下面是 维基百科 Base64 中的介绍,其实自己实现起 ...

  2. 配置SharePoint环境加域提示网络名不可用[已解决]

    今天去客户给机器做备机,带着装好SharePoint07的机器跑过去了,先做个LAN,然后连上机器开始工作:首先当然是改ip地址,然后都改好了开始加域,加了好几次,发现都不行,提示"指定的网 ...

  3. solr研磨之性能调优

    作者:战斗民族就是干  转载请注明地址:http://www.cnblogs.com/prayers/p/8982141.html 本篇文章我们来了解一下solr的性能方面的调优,分为Schema优化 ...

  4. 从JavaWeb危险字符过滤浅谈ESAPI使用

    事先声明:只是浅谈,我也之用了这个组件的一点点. 又到某重要XX时期(但愿此文给面临此需求的同仁有所帮助),某Web应用第一次面临安全加固要求,AppScan的安全测试报告还是很清爽的,内容全面,提示 ...

  5. How To Install and Use Redis

    https://www.digitalocean.com/community/tutorials/how-to-install-and-use-Redis About Redis redis, dev ...

  6. /usr/lib/uwsgi/plugins/python_plugin.so: cannot open shared object file: No such file or directory

    Django uwsgi部署方式下产生这个Bug,后来发现把uwsgi配置ini文件里面的 #plugins = python 把上面这句配置语句注释掉,uwsgi就可以运行了,当然,是正常可用运行状 ...

  7. laravel 5.5 安装

    PHP要求 PHP> = 7.0.0 OpenSSL PHP扩展 PDO PHP扩展 Mbstring PHP扩展 Tokenizer PHP扩展 XML PHP扩展 通过Composer创建项 ...

  8. css初始化标签属性--源码

    body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, p, blockquote ...

  9. php 微信JS-SDK封装类

    JSSDK使用步骤: 步骤一:绑定域名 步骤二:引入JS文件 步骤三:通过config接口注入权限验证配置 步骤四:通过ready接口处理成功验证 步骤五:通过error接口处理失败验证 具体步骤方法 ...

  10. AE、AS调用时用代码提供许可(不需要添加LicenseControl控件)

    private void CheckBindLicense() { ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.EngineOrDe ...