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 实现
gin
的 Context
中包含了*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 请求参数校验。
Multipart client实现
multipart form 的 client 写法示例
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
}
总结
Gin 的实现方式更加简单高效,框架为我们封装了很多细节。使用起来更加方便。标准库实现相对而言也算简单。但是需要我们自己组织和校验请求参数。
参考
gin
https://gist.github.com/mattetti/5914158
golang 上传文件(包括 gin 实现)的更多相关文章
- Gin 08 上传文件
单文件上传 cat index.html <!DOCTYPE html> <html lang="en"> <head> <meta ch ...
- Ajax表单异步上传(包括文件域)
起因 做前台页面时,需要调用WebAPI的Post请求,发送一些字段和文件(相当于把表单通过ajax异步发送出去,得到返回结果),然后得到返回值判断是否成功. 尝试 先是尝试了一下 "jQu ...
- CXF:通过WebService上传文件,包括大文件的处理
参考网上文章,用CXF发布上传文件接口,并上传大文件的测试. 框架:spring3.1+cxf2.7.6 1.定义文件类实体 import javax.activation.DataHandler; ...
- C# 对sharepoint 列表的一些基本操作,包括添加/删除/查询/上传文件给sharepoint list添加数据
转载:http://www.cnblogs.com/kivenhou/archive/2013/02/22/2921954.html 操作List前请设置SPWeb的allowUnsafeUpdate ...
- H5利用formData来上传文件(包括图片,doc,pdf等各种格式)方法小结!
H5页面中我们常需要进行文件上传,那么怎么来实现这个功能呢??? 我主要谈如下两种方法. (一).传统的form表单方法 <form action="/Home/SaveFile1&q ...
- fetch上传文件报错的问题(multipart: NextPart: EOF)
技术栈 后台: gin(golang) 前端: react+antd+dva 问题 前端这边使用fetch发送http请求的时候,后端解析formData报错: multipart: NextPart ...
- 再看ftp上传文件
前言 去年在项目中用到ftp上传文件,用FtpWebRequest和FtpWebResponse封装一个帮助类,这个在网上能找到很多,前台使用Uploadify控件,然后在服务器上搭建Ftp服务器,在 ...
- java http工具类和HttpUrlConnection上传文件分析
利用java中的HttpUrlConnection上传文件,我们其实只要知道Http协议上传文件的标准格式.那么就可以用任何一门语言来模拟浏览器上传文件.下面有几篇文章从http协议入手介绍了java ...
- 为什么上传文件的表单里面要加一个属性enctype=multipart/form-data?
首先知道enctype这个属性管理的是表单的MIME编码.共有三个值可选:1.application/x-www-form-urlencoded2.multipart/form-data3.text/ ...
随机推荐
- colormap是MATLAB里面用来设定和获取当前色图的函数。
下面将举例.描述MATLAB内建的色图.用户除了可以编程指定MATLAB内建的色图,还可以使用Plot Tools图形用具界面的Figure Properties面板中的Colormap菜单来选择一种 ...
- js 对象 toJSON 方法
浅谈 js 对象 toJSON 方法 前些天在<浅谈 JSON.stringify 方法>说了他的正确使用姿势,今天来说下 toJSON 方法吧.其实我觉得这货跟 toString 一 ...
- 《Linux设备驱动程序》第三版 scull编译 Ubuntu18.04
0 准备工作. 0.0 系统环境:Ubuntu18.04.1 amd64. 0.1 安装必要软件包 1 sudo apt install build-essential bison flex libs ...
- Javascript/CSS/HTML/vue/angularJS/react/jquery/DOM前端编程经典电子书pdf下载
高级进阶必读 你所不知道的系列,高级开发必掌握. JavaScript这门语言简单易用,很容易上手,但其语言机制复杂微妙,即使是经验丰富的JavaScript开发人员,如果没有认真学习的话也无法真正理 ...
- Android通过ksoap2这个框架调用webservice大讲堂
昨天有人问我Android怎么连接mysql数据库,和对数据库的操作呀,我想把,给他说说json通信,可是他并不知道怎么弄,哎算了吧,直接叫他用ksoap吧,给他说了大半天,好多零碎的知识,看来还是有 ...
- android -------- java.net.UnknownServiceException
最近升级了Android的API版本时 ,导致我的网络请求失败了, 出现了这个错误 java.net.UnknownServiceException, 这个错误,我在网上查到这个主要是由于,我们的Ok ...
- 007 搜索API
1.说明 这个API用于在elasticsearch中搜索内容,用户可以通过发送以查询字符串为参数的get请求进行搜索,也可以在post请求的消息体中进行查询. 2.多索引 允许搜索所有的索引或某些特 ...
- Android输入法遮挡了输入框,使用android:fitsSystemWindows="true"后界面顶部出现白条解决方案
我的最外层是LinearLayout,自定义CustomLinearLayout继承LinearLayout,重写fitSystemWindows和onApplyWindowInsets两个方法: p ...
- 【转载】 Bill Gates和Elon Musk推荐,人工智能必读的三本书 -《终极算法》,《超级智能》和《终极发明》
原文地址: https://blog.csdn.net/ztf312/article/details/80761917 ---------------------------------------- ...
- [转]Winform打包工具SetupFactory 9 的使用
写了个WinForm的小程序..以前没打过包..只是直接把Bin里的东西复制出来使用..自己使用是足够.但是发给别人毕竟不太好看(不牛逼)..所以就想着打包.. Vs2012自带的有打包的功能..相信 ...