golang 上传文件(包括 gin 实现)
golang web服务有时候需要提供上传文件的接口,以下就是具体示例。为了示例简单(吐槽下 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 请求格式中。值是以键值对的形式传递的。 标准包实现可以使用 文件参数files :=r.MultipartForm.File files 是 值参数values := r.MultipartForm.Value values 是 Gin 实现
type newForm struct { UploadKey *multipart.FileHeader `form:"upload-key"` Name string `form:"name"` Age int `form:"age"` } 在获取 form 的时候直接使用 var form newForm if err := c.ShouldBind(&form); err != nil{ //ignore } 同时 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:%sn",err.Error()) return } client := &http.Client{} resp,err := client.Do(req) if err != nil { fmt.Printf("error to request to the server:%sn",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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |