文件上传

gf支持非常方便的表单文件上传功能,并且HTTP客户端对上传功能进行了必要的封装并极大简化了上传功能调用。

服务端

https://github.com/gogf/gf/blob/master/.example/net/ghttp/client/upload/server.go

  1. package main
  2. import (
  3. "github.com/gogf/gf/frame/g"
  4. "github.com/gogf/gf/net/ghttp"
  5. "github.com/gogf/gf/os/gfile"
  6. "io"
  7. )
  8. // Upload uploads files to /tmp .
  9. func Upload(r *ghttp.Request) {
  10. saveDir := "/tmp/"
  11. for _, item := range r.GetMultipartFiles("upload-file") {
  12. file, err := item.Open()
  13. if err != nil {
  14. r.Response.Write(err)
  15. return
  16. }
  17. defer file.Close()
  18. f, err := gfile.Create(saveDir + gfile.Basename(item.Filename))
  19. if err != nil {
  20. r.Response.Write(err)
  21. return
  22. }
  23. defer f.Close()
  24. if _, err := io.Copy(f, file); err != nil {
  25. r.Response.Write(err)
  26. return
  27. }
  28. }
  29. r.Response.Write("upload successfully")
  30. }
  31. // UploadShow shows uploading simgle file page.
  32. func UploadShow(r *ghttp.Request) {
  33. r.Response.Write(`
  34. <html>
  35. <head>
  36. <title>GF Upload File Demo</title>
  37. </head>
  38. <body>
  39. <form enctype="multipart/form-data" action="/upload" method="post">
  40. <input type="file" name="upload-file" />
  41. <input type="submit" value="upload" />
  42. </form>
  43. </body>
  44. </html>
  45. `)
  46. }
  47. // UploadShowBatch shows uploading multiple files page.
  48. func UploadShowBatch(r *ghttp.Request) {
  49. r.Response.Write(`
  50. <html>
  51. <head>
  52. <title>GF Upload Files Demo</title>
  53. </head>
  54. <body>
  55. <form enctype="multipart/form-data" action="/upload" method="post">
  56. <input type="file" name="upload-file" />
  57. <input type="file" name="upload-file" />
  58. <input type="submit" value="upload" />
  59. </form>
  60. </body>
  61. </html>
  62. `)
  63. }
  64. func main() {
  65. s := g.Server()
  66. s.Group("/upload", func(group *ghttp.RouterGroup) {
  67. group.ALL("/", Upload)
  68. group.ALL("/show", UploadShow)
  69. group.ALL("/batch", UploadShowBatch)
  70. })
  71. s.SetPort(8199)
  72. s.Run()
  73. }

该服务端提供了3个接口:

  1. http://127.0.0.1:8199/upload/show 地址用于展示单个文件上传的H5页面;
  2. http://127.0.0.1:8199/upload/batch 地址用于展示多个文件上传的H5页面;
  3. http://127.0.0.1:8199/upload 接口用于真实的表单文件上传,该接口同时支持单个文件或者多个文件上传;

我们这里访问 http://127.0.0.1:8199/upload/show 选择需要上传的单个文件,提交之后可以看到文件上传成功到服务器上。

服务端处理文件上传比较简单,但是需要注意以下几点:

  1. 服务端在上传处理中需要使用defer file.Close()关闭掉临时上传文件指针;
  2. 将上传文件转存到其他文件目录时,需要通过gfile.Create新建文件,并通过io.Copy(file, f)将文件内存写入到新文件中,由于这里使用的是流式读写方式,因此对于服务端的内存占用会比较友好;
  3. 需要使用defer f.Close()关闭创建的文件指针;

客户端

单文件上传

https://github.com/gogf/gf/blob/master/.example/net/ghttp/client/upload/client.go

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/net/ghttp"
  5. "github.com/gogf/gf/os/glog"
  6. )
  7. func main() {
  8. path := "/home/john/Workspace/Go/github.com/gogf/gf/version.go"
  9. r, e := ghttp.Post("http://127.0.0.1:8199/upload", "upload-file=@file:"+path)
  10. if e != nil {
  11. glog.Error(e)
  12. } else {
  13. fmt.Println(string(r.ReadAll()))
  14. r.Close()
  15. }
  16. }

注意到了吗?文件上传参数格式使用了 参数名=@file:文件路径 ,HTTP客户端将会自动解析文件路径对应的文件内容并读取提交给服务端。原本复杂的文件上传操作被gf进行了封装处理,用户只需要使用 @file:+文件路径 来构成参数值即可。其中,文件路径请使用本地文件绝对路径。

首先运行服务端程序之后,我们再运行这个上传客户端(注意修改上传的文件路径为本地真实文件路径),执行后可以看到文件被成功上传到服务器的指定路径下。

多文件上传

https://github.com/gogf/gf/blob/master/.example/net/ghttp/client/upload-batch/client.go

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/net/ghttp"
  5. "github.com/gogf/gf/os/glog"
  6. )
  7. func main() {
  8. path1 := "/Users/john/Pictures/logo1.png"
  9. path2 := "/Users/john/Pictures/logo2.png"
  10. r, e := ghttp.Post(
  11. "http://127.0.0.1:8199/upload",
  12. fmt.Sprintf(`upload-file=@file:%s&upload-file=@file:%s`, path1, path2),
  13. )
  14. if e != nil {
  15. glog.Error(e)
  16. } else {
  17. fmt.Println(string(r.ReadAll()))
  18. r.Close()
  19. }
  20. }

可以看到,多个文件上传提交参数格式为参数名=@file:xxx&参数名=@file:xxx...,也可以使用参数名[]=@file:xxx&参数名[]=@file:xxx...的形式。

首先运行服务端程序之后,我们再运行这个上传客户端(注意修改上传的文件路径为本地真实文件路径),执行后可以看到文件被成功上传到服务器的指定路径下。