强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Go 语言完全指南 / 25 - Web 框架:Gin、Echo、Chi、路由、中间件

25 - Web 框架

25.1 Gin

Gin 是 Go 最流行的 Web 框架,性能优秀,API 简洁。

package main

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

func main() {
    r := gin.Default() // 带 Logger 和 Recovery 中间件

    // 路由组
    v1 := r.Group("/api/v1")
    {
        v1.GET("/users", listUsers)
        v1.POST("/users", createUser)
        v1.GET("/users/:id", getUser)
        v1.PUT("/users/:id", updateUser)
        v1.DELETE("/users/:id", deleteUser)
    }

    r.Run(":8080")
}

func listUsers(c *gin.Context) {
    page := c.DefaultQuery("page", "1")
    size := c.DefaultQuery("size", "10")
    c.JSON(http.StatusOK, gin.H{
        "page":  page,
        "size":  size,
        "users": []gin.H{},
    })
}

func createUser(c *gin.Context) {
    var req struct {
        Name  string `json:"name" binding:"required"`
        Email string `json:"email" binding:"required,email"`
        Age   int    `json:"age" binding:"gte=0,lte=150"`
    }
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    c.JSON(http.StatusCreated, gin.H{
        "id":    1,
        "name":  req.Name,
        "email": req.Email,
    })
}

func getUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(http.StatusOK, gin.H{
        "id":   id,
        "name": "Alice",
    })
}

func updateUser(c *gin.Context) {
    id := c.Param("id")
    var req struct {
        Name string `json:"name"`
    }
    c.ShouldBindJSON(&req)
    c.JSON(http.StatusOK, gin.H{"id": id, "name": req.Name})
}

func deleteUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(http.StatusOK, gin.H{"message": "User " + id + " deleted"})
}

Gin 中间件

// 自定义中间件
func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
            return
        }
        // 验证 token...
        c.Set("user_id", 123)
        c.Next()
    }
}

// 使用中间件
authorized := r.Group("/api", AuthMiddleware())
{
    authorized.GET("/profile", getProfile)
}

Gin 响应工具

// 统一响应结构
type Response struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Data    any    `json:"data,omitempty"`
}

func success(c *gin.Context, data any) {
    c.JSON(http.StatusOK, Response{
        Code:    0,
        Message: "success",
        Data:    data,
    })
}

func fail(c *gin.Context, code int, msg string) {
    c.JSON(code, Response{
        Code:    code,
        Message: msg,
    })
}

25.2 Echo

import (
    "github.com/labstack/echo/v4"
    "github.com/labstack/echo/v4/middleware"
)

func main() {
    e := echo.New()
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.CORS())

    e.GET("/users", listUsers)
    e.POST("/users", createUser)
    e.GET("/users/:id", getUser)

    e.Logger.Fatal(e.Start(":8080"))
}

func listUsers(c echo.Context) error {
    page := c.QueryParam("page")
    return c.JSON(200, map[string]any{
        "page":   page,
        "users":  []any{},
    })
}

func createUser(c echo.Context) error {
    var req struct {
        Name  string `json:"name"`
        Email string `json:"email"`
    }
    if err := c.Bind(&req); err != nil {
        return echo.NewHTTPError(400, err.Error())
    }
    return c.JSON(201, req)
}

func getUser(c echo.Context) error {
    id := c.Param("id")
    return c.JSON(200, map[string]string{"id": id, "name": "Alice"})
}

25.3 Chi

轻量级、兼容 net/http 的路由框架。

import (
    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
)

func main() {
    r := chi.NewRouter()
    r.Use(middleware.Logger)
    r.Use(middleware.Recoverer)
    r.Use(middleware.Timeout(60 * time.Second))

    r.Route("/api", func(r chi.Router) {
        r.Route("/users", func(r chi.Router) {
            r.Get("/", listUsers)
            r.Post("/", createUser)

            r.Route("/{id}", func(r chi.Router) {
                r.Get("/", getUser)
                r.Put("/", updateUser)
                r.Delete("/", deleteUser)
            })
        })
    })

    http.ListenAndServe(":8080", r)
}

func getUser(w http.ResponseWriter, r *http.Request) {
    id := chi.URLParam(r, "id")
    json.NewEncoder(w).Encode(map[string]string{"id": id, "name": "Alice"})
}

25.4 框架对比

特性GinEchoChinet/http
路由性能⚡ 高⚡ 高⚡ 高🟡 中
API 风格独特独特兼容 net/http原生
中间件需自己实现
学习曲线
生态系统最丰富丰富中等标准库
文档质量⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

选择建议

  • 快速开发:Gin(生态最丰富,文档最好)
  • 兼容标准库:Chi(完全兼容 net/http handler)
  • 极简风格:Echo(API 简洁清晰)
  • 无依赖:net/http(Go 1.22+ 增强路由已够用)

25.5 项目结构示例

myproject/
├── main.go
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── handler/          # HTTP 处理器
│   │   ├── user.go
│   │   └── user_test.go
│   ├── middleware/       # 中间件
│   │   ├── auth.go
│   │   └── logging.go
│   ├── model/           # 数据模型
│   │   └── user.go
│   ├── service/         # 业务逻辑
│   │   └── user.go
│   └── repository/      # 数据访问
│       └── user.go
├── config/
│   └── config.go
├── go.mod
└── go.sum
// 分层架构示例
// handler -> service -> repository

// handler/user.go
type UserHandler struct {
    service *service.UserService
}

func (h *UserHandler) GetUser(c *gin.Context) {
    id, _ := strconv.Atoi(c.Param("id"))
    user, err := h.service.GetByID(id)
    if err != nil {
        c.JSON(404, gin.H{"error": "User not found"})
        return
    }
    c.JSON(200, user)
}

// service/user.go
type UserService struct {
    repo repository.UserRepository
}

func (s *UserService) GetByID(id int) (*model.User, error) {
    return s.repo.FindByID(id)
}

// repository/user.go
type UserRepository interface {
    FindByID(id int) (*model.User, error)
    Save(user *model.User) error
}

🏢 业务场景

  1. REST API 服务:Gin/Chi 构建用户、订单等 API
  2. 微服务网关:Chi 实现 API Gateway
  3. 管理后台:Gin + 模板渲染管理界面
  4. 原型开发:Gin 快速搭建 API 原型

📖 扩展阅读