diff --git a/.example/net/ghttp/client/upload-batch/client.go b/.example/net/ghttp/client/upload-batch/client.go new file mode 100644 index 000000000..492c5e421 --- /dev/null +++ b/.example/net/ghttp/client/upload-batch/client.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + + "github.com/gogf/gf/net/ghttp" + "github.com/gogf/gf/os/glog" +) + +func main() { + path := "/home/john/Workspace/Go/github.com/gogf/gf/version.go" + r, e := ghttp.Post("http://127.0.0.1:8199/upload", "name=john&age=18&upload-file=@file:"+path) + if e != nil { + glog.Error(e) + } else { + fmt.Println(string(r.ReadAll())) + r.Close() + } +} diff --git a/.example/net/ghttp/client/upload-batch/server.go b/.example/net/ghttp/client/upload-batch/server.go new file mode 100644 index 000000000..8e9e03776 --- /dev/null +++ b/.example/net/ghttp/client/upload-batch/server.go @@ -0,0 +1,61 @@ +package main + +import ( + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/net/ghttp" + "github.com/gogf/gf/os/gfile" + "io" +) + +// Upload uploads files to /tmp . +func Upload(r *ghttp.Request) { + saveDir := "/tmp/" + for _, item := range r.GetMultiPartFiles("upload-file") { + file, err := item.Open() + if err != nil { + r.Response.Write(err) + return + } + defer file.Close() + + f, err := gfile.Create(saveDir + gfile.Basename(item.Filename)) + if err != nil { + r.Response.Write(err) + return + } + defer f.Close() + + if _, err := io.Copy(f, file); err != nil { + r.Response.Write(err) + return + } + } + r.Response.Write("upload successfully") +} + +// UploadShow shows uploading page. +func UploadShow(r *ghttp.Request) { + r.Response.Write(` + + + GF UploadFile Demo + + +
+ + +
+ + + `) +} + +func main() { + s := g.Server() + s.Group("/upload", func(g *ghttp.RouterGroup) { + g.ALL("/", Upload) + g.ALL("/show", UploadShow) + }) + s.SetPort(8199) + s.Run() +} diff --git a/net/ghttp/ghttp_request.go b/net/ghttp/ghttp_request.go index d3ee68248..c983cc18c 100644 --- a/net/ghttp/ghttp_request.go +++ b/net/ghttp/ghttp_request.go @@ -9,6 +9,7 @@ package ghttp import ( "fmt" "io/ioutil" + "mime/multipart" "net/http" "strings" @@ -41,6 +42,7 @@ type Request struct { parsedPost bool // POST参数是否已经解析 parsedDelete bool // DELETE参数是否已经解析 parsedRaw bool // 原始参数是否已经解析 + parsedForm bool // 是否已调用r.ParseMultipartForm getMap map[string]interface{} // GET解析参数 putMap map[string]interface{} // PUT解析参数 postMap map[string]interface{} // POST解析参数 @@ -208,6 +210,18 @@ func (r *Request) GetHost() string { return r.parsedHost } +// 获取上传的文件列表 +func (r *Request) GetMultiPartFiles(name string) []*multipart.FileHeader { + if !r.parsedForm { + r.ParseMultipartForm(r.Server.config.FormParsingMemory) + r.parsedForm = true + } + if r.MultipartForm == nil { + return nil + } + return r.MultipartForm.File[name] +} + // 判断是否为静态文件请求 func (r *Request) IsFileRequest() bool { return r.isFileRequest diff --git a/net/ghttp/ghttp_request_method_post.go b/net/ghttp/ghttp_request_method_post.go index 46006ca4a..2923589fe 100644 --- a/net/ghttp/ghttp_request_method_post.go +++ b/net/ghttp/ghttp_request_method_post.go @@ -22,7 +22,10 @@ func (r *Request) initPost() { r.parsedPost = true if v := r.Header.Get("Content-Type"); v != "" && gstr.Contains(v, "multipart/") { // multipart/form-data, multipart/mixed - r.ParseMultipartForm(r.Server.config.FormParsingMemory) + if !r.parsedForm { + r.ParseMultipartForm(r.Server.config.FormParsingMemory) + r.parsedForm = true + } if len(r.PostForm) > 0 { // 重新组织数据格式,使用统一的数据Parse方式 params := ""