GoFrame
supports very convenient form file uploading functionality, and the HTTP client has encapsulated the upload functionality to simplify the calling of the upload feature significantly.
Note: The upload file size is affected by the ClientMaxBodySize
configuration of ghttp.Server
: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp#ServerConfig. The default supported upload file size is 8MB
.
Server
On the server side, use the Request
object to get the uploaded files:
package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
)
// Upload uploads files to /tmp .
func Upload(r *ghttp.Request) {
files := r.GetUploadFiles("upload-file")
names, err := files.Save("/tmp/")
if err != nil {
r.Response.WriteExit(err)
}
r.Response.WriteExit("upload successfully: ", names)
}
// UploadShow shows uploading single file page.
func UploadShow(r *ghttp.Request) {
r.Response.Write(`
<html>
<head>
<title>GoFrame Upload File Demo</title>
</head>
<body>
<form enctype="multipart/form-data" action="/upload" method="post">
<input type="file" name="upload-file" />
<input type="submit" value="upload" />
</form>
</body>
</html>
`)
}
// UploadShowBatch shows uploading multiple files page.
func UploadShowBatch(r *ghttp.Request) {
r.Response.Write(`
<html>
<head>
<title>GoFrame Upload Files Demo</title>
</head>
<body>
<form enctype="multipart/form-data" action="/upload" method="post">
<input type="file" name="upload-file" />
<input type="file" name="upload-file" />
<input type="submit" value="upload" />
</form>
</body>
</html>
`)
}
func main() {
s := g.Server()
s.Group("/upload", func(group *ghttp.RouterGroup) {
group.POST("/", Upload)
group.ALL("/show", UploadShow)
group.ALL("/batch", UploadShowBatch)
})
s.SetPort(8199)
s.Run()
}
The server provides three APIs:
- http://127.0.0.1:8199/upload/show for displaying a single file upload H5 page;
- http://127.0.0.1:8199/upload/batch for displaying a multiple files upload H5 page;
- http://127.0.0.1:8199/upload API for real form file uploading, supporting both single and multiple file uploads.
Visit http://127.0.0.1:8199/upload/show to choose a single file to upload. After submitting, you can see that the file has been successfully uploaded to the server.
Key Code Explanation
- On the server side, we can obtain all uploaded file objects using the
r.GetUploadFiles
method, or a single uploaded file object usingr.GetUploadFile
. - The parameter
"upload-file"
inr.GetUploadFiles("upload-file")
is the form file field name during the client-side upload in this example. Developers can define this on the client-side according to front-end and back-end agreements to facilitate the server-side's reception of form file fields. - Using
files.Save
, you can conveniently save multiple uploaded files to the specified directory and return the successfully saved file names. If a batch save operation is taking place, any single file save failure will immediately return an error. Additionally, theSave
method's second parameter supports randomly auto-naming the uploaded files. - The route registered with
group.POST("/", Upload)
only supports access viaPOST
.
Client
Single File Upload
package main
import (
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
)
func main() {
var (
ctx = gctx.New()
path = "/home/john/Workspace/Go/github.com/gogf/gf/v2/version.go"
)
result, err := g.Client().Post(ctx, "http://127.0.0.1:8199/upload", "upload-file=@file:"+path)
if err != nil {
glog.Fatalf(ctx, `%+v`, err)
}
defer result.Close()
fmt.Println(result.ReadAllString())
}
Did you notice? The file upload parameter format uses parameter-name=@file:file-path
. The HTTP client will automatically parse the file content corresponding to the file path and read it to the server. The originally complicated file upload operation is encapsulated by gf
, and users only need to use @file:+file-path
to form the parameter value. The file-path
should use the local file's absolute path.
First, run the server program, then run this upload client (make sure to modify the upload file path to the actual file path locally), and upon execution, you can see the file being successfully uploaded to the specified path on the server.
Multiple File Upload
package main
import (
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
)
func main() {
var (
ctx = gctx.New()
path1 = "/Users/john/Pictures/logo1.png"
path2 = "/Users/john/Pictures/logo2.png"
)
result, err := g.Client().Post(
ctx,
"http://127.0.0.1:8199/upload",
fmt.Sprintf(`upload-file=@file:%s&upload-file=@file:%s`, path1, path2),
)
if err != nil {
glog.Fatalf(ctx, `%+v`, err)
}
defer result.Close()
fmt.Println(result.ReadAllString())
}
As can be seen, the multiple file upload submission parameter format is parameter-name=@file:xxx¶meter-name=@file:xxx...
, and can also be in the form of parameter-name[]=@file:xxx¶meter-name[]=@file:xxx...
.
First, run the server program, then run this upload client (make sure to modify the upload file path to the actual file path locally), and upon execution, you can see the files being successfully uploaded to the specified path on the server.
Custom File Name
It's very simple, modify the FileName
property.
s := g.Server()
s.BindHandler("/upload", func(r *ghttp.Request) {
file := r.GetUploadFile("TestFile")
if file == nil {
r.Response.Write("empty file")
return
}
file.Filename = "MyCustomFileName.txt"
fileName, err := file.Save(gfile.TempDir())
if err != nil {
r.Response.Write(err)
return
}
r.Response.Write(fileName)
})
s.SetPort(8999)
s.Run()
Standardized Routing to Receive Uploaded Files
If the server uses standardized routing, structured parameters can be used to retrieve uploaded files:
- The data type for receiving parameters uses
*ghttp.UploadFile
. - If the API documentation should also support file types, set
type
tofile
in the parameter tags.