第一个应用 #

一、Hello World #

1.1 创建项目 #

bash
# 创建项目目录
mkdir hello-gin
cd hello-gin

# 初始化模块
go mod init hello-gin

# 安装Gin
go get -u github.com/gin-gonic/gin

1.2 编写代码 #

创建 main.go 文件:

go
package main

import "github.com/gin-gonic/gin"

func main() {
    // 创建默认路由引擎
    r := gin.Default()
    
    // 定义GET路由
    r.GET("/", func(c *gin.Context) {
        c.String(200, "Hello, Gin!")
    })
    
    // 启动HTTP服务,默认在0.0.0.0:8080启动服务
    r.Run()
}

1.3 运行项目 #

bash
# 运行项目
go run main.go

# 输出
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] Listening and serving HTTP on :8080

1.4 测试接口 #

bash
# 使用curl测试
curl http://localhost:8080/

# 输出
Hello, Gin!

二、代码解析 #

2.1 创建路由引擎 #

go
// 创建带有默认中间件的路由
r := gin.Default()

// 等价于
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())

// 创建不带中间件的路由
r := gin.New()

2.2 定义路由 #

go
// GET请求
r.GET("/get", func(c *gin.Context) {
    c.String(200, "GET request")
})

// POST请求
r.POST("/post", func(c *gin.Context) {
    c.String(200, "POST request")
})

// PUT请求
r.PUT("/put", func(c *gin.Context) {
    c.String(200, "PUT request")
})

// DELETE请求
r.DELETE("/delete", func(c *gin.Context) {
    c.String(200, "DELETE request")
})

// PATCH请求
r.PATCH("/patch", func(c *gin.Context) {
    c.String(200, "PATCH request")
})

// HEAD请求
r.HEAD("/head", func(c *gin.Context) {
    c.String(200, "HEAD request")
})

// OPTIONS请求
r.OPTIONS("/options", func(c *gin.Context) {
    c.String(200, "OPTIONS request")
})

// 匹配所有HTTP方法
r.Any("/any", func(c *gin.Context) {
    c.String(200, "Any request")
})

2.3 处理函数 #

go
// 匿名函数
r.GET("/anonymous", func(c *gin.Context) {
    c.String(200, "Anonymous function")
})

// 命名函数
func helloHandler(c *gin.Context) {
    c.String(200, "Named function")
}
r.GET("/named", helloHandler)

// 方法绑定
type UserController struct{}

func (u *UserController) Hello(c *gin.Context) {
    c.String(200, "Method handler")
}
user := &UserController{}
r.GET("/method", user.Hello)

2.4 启动服务器 #

go
// 默认端口8080
r.Run()

// 指定端口
r.Run(":3000")

// 指定地址和端口
r.Run("127.0.0.1:3000")

// 使用http.Server
r := gin.Default()
s := &http.Server{
    Addr:           ":8080",
    Handler:        r,
    ReadTimeout:    10 * time.Second,
    WriteTimeout:   10 * time.Second,
    MaxHeaderBytes: 1 << 20,
}
s.ListenAndServe()

三、Context上下文 #

3.1 Context简介 #

Context是Gin的核心,封装了请求和响应:

go
func handler(c *gin.Context) {
    // c.Request  - http.Request
    // c.Writer   - http.ResponseWriter
}

3.2 获取请求参数 #

go
r.GET("/query", func(c *gin.Context) {
    // 获取查询参数
    name := c.Query("name")           // 获取name参数
    name = c.DefaultQuery("name", "Guest")  // 带默认值
    
    // 获取所有查询参数
    values := c.Request.URL.Query()
    
    c.String(200, "Hello %s", name)
})

3.3 获取路径参数 #

go
// 获取路径参数
r.GET("/user/:id", func(c *gin.Context) {
    id := c.Param("id")
    c.String(200, "User ID: %s", id)
})

// 获取可选路径参数
r.GET("/user/:id/*action", func(c *gin.Context) {
    id := c.Param("id")
    action := c.Param("action")
    c.String(200, "User ID: %s, Action: %s", id, action)
})

3.4 获取表单数据 #

go
r.POST("/form", func(c *gin.Context) {
    // 获取表单数据
    username := c.PostForm("username")
    password := c.DefaultPostForm("password", "")
    
    c.String(200, "Username: %s, Password: %s", username, password)
})

3.5 获取JSON数据 #

go
r.POST("/json", func(c *gin.Context) {
    // 方式1:绑定到map
    var json map[string]interface{}
    if err := c.BindJSON(&json); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    
    // 方式2:绑定到结构体
    type User struct {
        Name string `json:"name"`
        Age  int    `json:"age"`
    }
    var user User
    if err := c.ShouldBindJSON(&user); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    
    c.JSON(200, gin.H{"user": user})
})

四、响应处理 #

4.1 字符串响应 #

go
r.GET("/string", func(c *gin.Context) {
    c.String(200, "Hello, World!")
})

// 格式化字符串
r.GET("/format", func(c *gin.Context) {
    name := "Gin"
    c.String(200, "Hello, %s!", name)
})

4.2 JSON响应 #

go
// 使用gin.H
r.GET("/json1", func(c *gin.Context) {
    c.JSON(200, gin.H{
        "message": "ok",
        "status":  200,
    })
})

// 使用结构体
r.GET("/json2", func(c *gin.Context) {
    type Response struct {
        Message string `json:"message"`
        Status  int    `json:"status"`
    }
    c.JSON(200, Response{
        Message: "ok",
        Status:  200,
    })
})

// 使用map
r.GET("/json3", func(c *gin.Context) {
    c.JSON(200, map[string]interface{}{
        "message": "ok",
        "status":  200,
    })
})

4.3 XML响应 #

go
r.GET("/xml", func(c *gin.Context) {
    c.XML(200, gin.H{
        "message": "ok",
        "status":  200,
    })
})

4.4 HTML响应 #

go
// 加载模板
r.LoadHTMLGlob("templates/*")

r.GET("/html", func(c *gin.Context) {
    c.HTML(200, "index.html", gin.H{
        "title": "Gin Demo",
    })
})

4.5 文件响应 #

go
// 返回文件
r.GET("/file", func(c *gin.Context) {
    c.File("/path/to/file.pdf")
})

// 文件下载
r.GET("/download", func(c *gin.Context) {
    c.Header("Content-Disposition", "attachment; filename=file.pdf")
    c.File("/path/to/file.pdf")
})

4.6 重定向 #

go
r.GET("/redirect", func(c *gin.Context) {
    c.Redirect(302, "/new-url")
})

r.GET("/new-url", func(c *gin.Context) {
    c.String(200, "Redirected!")
})

五、完整示例 #

5.1 RESTful API示例 #

go
package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

type User struct {
    ID   string `json:"id"`
    Name string `json:"name"`
    Age  int    `json:"age"`
}

var users = []User{
    {ID: "1", Name: "Alice", Age: 25},
    {ID: "2", Name: "Bob", Age: 30},
}

func main() {
    r := gin.Default()
    
    // 获取所有用户
    r.GET("/users", func(c *gin.Context) {
        c.JSON(http.StatusOK, users)
    })
    
    // 获取单个用户
    r.GET("/users/:id", func(c *gin.Context) {
        id := c.Param("id")
        for _, user := range users {
            if user.ID == id {
                c.JSON(http.StatusOK, user)
                return
            }
        }
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
    })
    
    // 创建用户
    r.POST("/users", func(c *gin.Context) {
        var user User
        if err := c.ShouldBindJSON(&user); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        users = append(users, user)
        c.JSON(http.StatusCreated, user)
    })
    
    // 更新用户
    r.PUT("/users/:id", func(c *gin.Context) {
        id := c.Param("id")
        var updatedUser User
        if err := c.ShouldBindJSON(&updatedUser); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }
        for i, user := range users {
            if user.ID == id {
                users[i] = updatedUser
                users[i].ID = id
                c.JSON(http.StatusOK, users[i])
                return
            }
        }
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
    })
    
    // 删除用户
    r.DELETE("/users/:id", func(c *gin.Context) {
        id := c.Param("id")
        for i, user := range users {
            if user.ID == id {
                users = append(users[:i], users[i+1:]...)
                c.JSON(http.StatusOK, gin.H{"message": "Deleted"})
                return
            }
        }
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
    })
    
    r.Run(":8080")
}

5.2 测试API #

bash
# 获取所有用户
curl http://localhost:8080/users

# 获取单个用户
curl http://localhost:8080/users/1

# 创建用户
curl -X POST http://localhost:8080/users \
  -H "Content-Type: application/json" \
  -d '{"id":"3","name":"Charlie","age":28}'

# 更新用户
curl -X PUT http://localhost:8080/users/1 \
  -H "Content-Type: application/json" \
  -d '{"id":"1","name":"Alice Updated","age":26}'

# 删除用户
curl -X DELETE http://localhost:8080/users/1

六、调试技巧 #

6.1 打印路由信息 #

go
func main() {
    r := gin.Default()
    
    r.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })
    
    // 打印所有路由
    routes := r.Routes()
    for _, route := range routes {
        fmt.Printf("%s %s\n", route.Method, route.Path)
    }
    
    r.Run()
}

6.2 请求日志 #

go
func main() {
    r := gin.Default()
    
    // 自定义日志格式
    gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) {
        log.Printf("[ROUTE] %s %s --> %s (%d handlers)\n", 
            httpMethod, absolutePath, handlerName, nuHandlers)
    }
    
    r.GET("/ping", func(c *gin.Context) {
        c.String(200, "pong")
    })
    
    r.Run()
}

6.3 使用pprof #

go
import "net/http/pprof"

func main() {
    r := gin.Default()
    
    // 注册pprof路由
    r.GET("/debug/pprof/*action", func(c *gin.Context) {
        c.Param("action", c.Param("action")[1:])
        http.HandlerFunc(pprof.Index).ServeHTTP(c.Writer, c.Request)
    })
    
    r.Run()
}

七、总结 #

7.1 核心要点 #

要点 说明
创建引擎 gin.Default() 或 gin.New()
定义路由 r.GET()、r.POST()等方法
处理函数 func(c *gin.Context)
启动服务 r.Run()
Context 请求上下文,获取参数和响应

7.2 下一步 #

现在你已经创建了第一个Gin应用,接下来让我们学习 项目结构,组织更复杂的项目!

最后更新:2026-03-28