文件上传
单文件
使用FormFile
方法可以获取到POST请求中上传的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| func main() { r := gin.Default() r.LoadHTMLFiles("upload.html")
r.GET("/upload", func(c *gin.Context) { c.HTML(http.StatusOK, "upload.html", nil) })
r.POST("/upload", func(c *gin.Context) { f, err := c.FormFile("f1") if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) } else { dst := fmt.Sprintf("./%s", f.Filename) c.SaveUploadedFile(f, dst) c.JSON(http.StatusOK, gin.H{ "status": "OK", }) } })
r.Run(":9090") }
|
多文件
请求头参数设置 Content-Type: multipart/form-data
,多文件上传请求为:
1 2 3 4
| curl -X POST http://localhost:8080/upload \ -F "upload[]=@/Users/appleboy/test1.zip" \ -F "upload[]=@/Users/appleboy/test2.zip" \ -H "Content-Type: multipart/form-data"
|
首先解析 multipart forms,然后获取文件列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| func main() { router := gin.Default() router.MaxMultipartMemory = 8 << 20 router.POST("/upload", func(c *gin.Context) { form, _ := c.MultipartForm() files := form.File["upload[]"]
for _, file := range files { log.Println(file.Filename)
c.SaveUploadedFile(file, dst) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) }) router.Run(":8080") }
|
重定向
HTTP重定向
使用Redirect
方法即可进行HTTP重定向:
1 2 3
| r.GET("/index", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, "http://www.baidu.com") })
|
通过 POST 方法进行 HTTP 重定向(这里可以使用 StatusMovedPermanently 301 状态码、StatusFound 302 状态码和 StatusSeeOther 303 状态码)。
1 2 3
| r.POST("/test", func(c *gin.Context) { c.Redirect(http.StatusFound, "/foo") })
|
303 状态码明确表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区别。
当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送。301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做。
路由重定向
可以使用HandleContext
函数继续处理,进行路由重定向:
1 2 3 4 5 6 7 8 9 10 11
| r.GET("/index1", func(c *gin.Context) { c.Request.URL.Path = "/index2" r.HandleContext(c) })
r.GET("/index2", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "OK", }) })
|
路由
普通路由
除了GET
、POST
、PUT
、DELETE
等HTTP请求方法外,还有一个可以匹配所有请求的Any
方法:
1 2 3 4 5
| r.Any("/index", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "OK", }) })
|
为没有配置处理函数的路由添加处理程序,默认情况下它返回404,下面的代码为没有匹配到的路由都返回404.html
页面:
1 2 3
| r.NoRoute(func(c *gin.Context) { c.HTML(http.StatusNotFound, "404.html", nil) })
|
路由组
将拥有共同URL前缀的路由划分为一个路由组。可以用Group
方法进行路由分组,习惯性一对{}
包裹同组的路由:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| func main() { r := gin.Default()
userGroup := r.Group("/user") { userGroup.GET("/index", func(c *gin.Context) { }) userGroup.GET("/login", func(c *gin.Context) { }) }
videoGroup := r.Group("/video") { videoGroup.GET("/index", func(c *gin.Context) { }) videoGroup.GET("/movie", func(c *gin.Context) { }) videoGroup.GET("/cartoon", func(c *gin.Context) { }) } r.Run(":9090") }
|
路由组支持嵌套:
1 2 3 4 5 6 7 8 9 10 11
| shopGroup := r.Group("/shop") { shopGroup.GET("/index", func(c *gin.Context) { }) phoneGroup := shopGroup.Group("/phone") { phoneGroup.GET("/iphone", func(c *gin.Context) { }) phoneGroup.GET("/xiaomi", func(c *gin.Context) { }) } }
|