Golang Gin(中)
快速入门
Using GET, POST, PUT, PATCH, DELETE and OPTIONS
func main() { // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() router.GET("/someGet", getting) router.POST("/somePost", posting) router.PUT("/somePut", putting) router.DELETE("/someDelete", deleting) router.PATCH("/somePatch", patching) router.HEAD("/someHead", head) router.OPTIONS("/someOptions", options) // By default it serves on :8080 unless a // PORT environment variable was defined. router.Run() // router.Run(":3000") for a hard coded port }
Parameters in path
func main() { router := gin.Default() // This handler will match /user/john but will not match /user/ or /user router.GET("/user/:name", func(c *gin.Context) { name := c.Param("name") c.String(http.StatusOK, "Hello %s", name) }) // However, this one will match /user/john/ and also /user/john/send // If no other routers match /user/john, it will redirect to /user/john/ router.GET("/user/:name/*action", func(c *gin.Context) { name := c.Param("name") action := c.Param("action") message := name + " is " + action c.String(http.StatusOK, message) }) // For each matched request Context will hold the route definition router.POST("/user/:name/*action", func(c *gin.Context) { c.FullPath() == "/user/:name/*action" // true }) router.Run(":8080") }
Querystring parameters
func main() { router := gin.Default() // Query string parameters are parsed using the existing underlying request object. // The request responds to a url matching: /welcome?firstname=Jane&lastname=Doe router.GET("/welcome", func(c *gin.Context) { firstname := c.DefaultQuery("firstname", "Guest") lastname := c.Query("lastname") // shortcut for c.Request.URL.Query().Get("lastname") c.String(http.StatusOK, "Hello %s %s", firstname, lastname) }) router.Run(":8080") }
Multipart/Urlencoded Form
func main() { router := gin.Default() router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("message") nick := c.DefaultPostForm("nick", "anonymous") c.JSON(200, gin.H{ "status": "posted", "message": message, "nick": nick, }) }) router.Run(":8080") }
Another example: query + post form
POST /post?id=1234&page=1 HTTP/1.1 Content-Type: application/x-www-form-urlencoded name=manu&message=this_is_great
func main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { id := c.Query("id") page := c.DefaultQuery("page", "0") name := c.PostForm("name") message := c.PostForm("message") fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message) }) router.Run(":8080") }
id: 1234; page: 1; name: manu; message: this_is_great
Map as querystring or postform parameters
POST /post?ids[a]=1234&ids[b]=hello HTTP/1.1 Content-Type: application/x-www-form-urlencoded names[first]=thinkerou&names[second]=tianou
func main() { router := gin.Default() router.POST("/post", func(c *gin.Context) { ids := c.QueryMap("ids") names := c.PostFormMap("names") fmt.Printf("ids: %v; names: %v", ids, names) }) router.Run(":8080") }
ids: map[b:hello a:1234]; names: map[second:tianou first:thinkerou]
Upload files
Single file
The filename is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done.
func main() { router := gin.Default() // Set a lower memory limit for multipart forms (default is 32 MiB) router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // single file file, _ := c.FormFile("file") log.Println(file.Filename) // Upload the file to specific dst. c.SaveUploadedFile(file, dst) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename)) }) router.Run(":8080") }
How to curl
:
curl -X POST http://localhost:8080/upload \ -F "file=@/Users/appleboy/test.zip" \ -H "Content-Type: multipart/form-data"
Multiple files
See the detail example code.
func main() { router := gin.Default() // Set a lower memory limit for multipart forms (default is 32 MiB) router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // Multipart form form, _ := c.MultipartForm() files := form.File["upload[]"] for _, file := range files { log.Println(file.Filename) // Upload the file to specific dst. c.SaveUploadedFile(file, dst) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files))) }) router.Run(":8080") }
How to curl
:
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"
Grouping routes
func main() { router := gin.Default() // Simple group: v1 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", readEndpoint) } // Simple group: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } router.Run(":8080") }
Blank Gin without middleware by default
Use
r := gin.New()
instead of
// Default With the Logger and Recovery middleware already attached r := gin.Default()
Using middleware
func main() { // Creates a router without any middleware by default r := gin.New() // Global middleware // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. // By default gin.DefaultWriter = os.Stdout r.Use(gin.Logger()) // Recovery middleware recovers from any panics and writes a 500 if there was one. r.Use(gin.Recovery()) // Per route middleware, you can add as many as you desire. r.GET("/benchmark", MyBenchLogger(), benchEndpoint) // Authorization group // authorized := r.Group("/", AuthRequired()) // exactly the same as: authorized := r.Group("/") // per group middleware! in this case we use the custom created // AuthRequired() middleware just in the "authorized" group. authorized.Use(AuthRequired()) { authorized.POST("/login", loginEndpoint) authorized.POST("/submit", submitEndpoint) authorized.POST("/read", readEndpoint) // nested group testing := authorized.Group("testing") testing.GET("/analytics", analyticsEndpoint) } // Listen and serve on 0.0.0.0:8080 r.Run(":8080") }
Custom Recovery behavior
func main() { // Creates a router without any middleware by default r := gin.New() // Global middleware // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. // By default gin.DefaultWriter = os.Stdout r.Use(gin.Logger()) // Recovery middleware recovers from any panics and writes a 500 if there was one. r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) { if err, ok := recovered.(string); ok { c.String(http.StatusInternalServerError, fmt.Sprintf("error: %s", err)) } c.AbortWithStatus(http.StatusInternalServerError) })) r.GET("/panic", func(c *gin.Context) { // panic with a string -- the custom middleware could save this to a database or report it to the user panic("foo") }) r.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "ohai") }) // Listen and serve on 0.0.0.0:8080 r.Run(":8080") }
How to write log file
func main() { // Disable Console Color, you don't need console color when writing the logs to file. gin.DisableConsoleColor() // Logging to a file. f, _ := os.Create("gin.log") gin.DefaultWriter = io.MultiWriter(f) // Use the following code if you need to write the logs to file and console at the same time. // gin.DefaultWriter = io.MultiWriter(f, os.Stdout) router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") }
Custom Log Format
func main() { router := gin.New() // LoggerWithFormatter middleware will write the logs to gin.DefaultWriter // By default gin.DefaultWriter = os.Stdout router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { // your custom format return fmt.Sprintf("%s - [%s] \"%s %s %s %d %s \"%s\" %s\"\n", param.ClientIP, param.TimeStamp.Format(time.RFC1123), param.Method, param.Path, param.Request.Proto, param.StatusCode, param.Latency, param.Request.UserAgent(), param.ErrorMessage, ) })) router.Use(gin.Recovery()) router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") }
Sample Output
::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" "
Controlling Log output coloring
By default, logs output on console should be colorized depending on the detected TTY.
Never colorize logs:
func main() { // Disable log's color gin.DisableConsoleColor() // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") }
Always colorize logs:
func main() { // Force log's color gin.ForceConsoleColor() // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() router.GET("/ping", func(c *gin.Context) { c.String(200, "pong") }) router.Run(":8080") }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix