路由参数 #

一、参数类型概述 #

Echo支持多种参数类型,满足不同的请求场景。

1.1 参数类型 #

text
┌─────────────────────────────────────────────────────────┐
│                    参数类型                              │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  路径参数 (Path Params)                                  │
│  └── /users/:id  →  c.Param("id")                       │
│                                                         │
│  查询参数 (Query Params)                                 │
│  └── /users?page=1&size=10  →  c.QueryParam("page")     │
│                                                         │
│  表单参数 (Form Values)                                  │
│  └── POST body: name=张三  →  c.FormValue("name")       │
│                                                         │
│  JSON参数 (JSON Body)                                    │
│  └── POST body: {"name":"张三"}  →  c.Bind(&user)       │
│                                                         │
│  请求头 (Headers)                                        │
│  └── Authorization: Bearer xxx  →  c.Request().Header   │
│                                                         │
│  Cookie                                                 │
│  └── session=abc123  →  c.Cookie("session")             │
│                                                         │
└─────────────────────────────────────────────────────────┘

二、路径参数 #

2.1 基本用法 #

使用 :param 定义路径参数:

go
e.GET("/users/:id", func(c echo.Context) error {
    id := c.Param("id")
    return c.String(http.StatusOK, "User ID: "+id)
})

测试:

bash
curl http://localhost:8080/users/123
User ID: 123

2.2 多个路径参数 #

go
e.GET("/users/:userId/posts/:postId", func(c echo.Context) error {
    userId := c.Param("userId")
    postId := c.Param("postId")
    
    return c.JSON(http.StatusOK, map[string]string{
        "userId": userId,
        "postId": postId,
    })
})

测试:

bash
curl http://localhost:8080/users/1/posts/100
{"userId":"1","postId":"100"}

2.3 通配符参数 #

使用 * 匹配任意路径:

go
e.GET("/files/*", func(c echo.Context) error {
    path := c.Param("*")
    return c.String(http.StatusOK, "File: "+path)
})

测试:

bash
curl http://localhost:8080/files/docs/readme.md
File: docs/readme.md

2.4 参数验证 #

go
e.GET("/users/:id", func(c echo.Context) error {
    id := c.Param("id")
    
    if _, err := strconv.Atoi(id); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "ID必须是数字")
    }
    
    return c.String(http.StatusOK, "User ID: "+id)
})

三、查询参数 #

3.1 基本用法 #

go
e.GET("/search", func(c echo.Context) error {
    q := c.QueryParam("q")
    return c.String(http.StatusOK, "Search: "+q)
})

测试:

bash
curl "http://localhost:8080/search?q=echo"
Search: echo

3.2 多个查询参数 #

go
e.GET("/users", func(c echo.Context) error {
    page := c.QueryParam("page")
    size := c.QueryParam("size")
    sort := c.QueryParam("sort")
    
    return c.JSON(http.StatusOK, map[string]string{
        "page": page,
        "size": size,
        "sort": sort,
    })
})

测试:

bash
curl "http://localhost:8080/users?page=1&size=10&sort=name"
{"page":"1","size":"10","sort":"name"}

3.3 默认值处理 #

go
e.GET("/users", func(c echo.Context) error {
    page := c.QueryParam("page")
    if page == "" {
        page = "1"
    }
    
    size := c.QueryParam("size")
    if size == "" {
        size = "10"
    }
    
    return c.JSON(http.StatusOK, map[string]string{
        "page": page,
        "size": size,
    })
})

3.4 QueryParams获取所有参数 #

go
e.GET("/filter", func(c echo.Context) error {
    params := c.QueryParams()
    
    result := make(map[string][]string)
    for key, values := range params {
        result[key] = values
    }
    
    return c.JSON(http.StatusOK, result)
})

测试:

bash
curl "http://localhost:8080/filter?tag=go&tag=echo&status=active"
{"status":["active"],"tag":["go","echo"]}

3.5 绑定查询参数 #

go
type PaginationQuery struct {
    Page int    `query:"page"`
    Size int    `query:"size"`
    Sort string `query:"sort"`
}

e.GET("/users", func(c echo.Context) error {
    q := new(PaginationQuery)
    if err := c.Bind(q); err != nil {
        return err
    }
    
    if q.Page == 0 {
        q.Page = 1
    }
    if q.Size == 0 {
        q.Size = 10
    }
    
    return c.JSON(http.StatusOK, q)
})

四、表单参数 #

4.1 基本用法 #

go
e.POST("/login", func(c echo.Context) error {
    username := c.FormValue("username")
    password := c.FormValue("password")
    
    return c.JSON(http.StatusOK, map[string]string{
        "username": username,
        "status":   "success",
    })
})

测试:

bash
curl -X POST -d "username=admin&password=123456" http://localhost:8080/login
{"username":"admin","status":"success"}

4.2 多值表单参数 #

go
e.POST("/tags", func(c echo.Context) error {
    tags := c.Request().Form["tags"]
    return c.JSON(http.StatusOK, map[string][]string{
        "tags": tags,
    })
})

测试:

bash
curl -X POST -d "tags=go&tags=echo&tags=web" http://localhost:8080/tags
{"tags":["go","echo","web"]}

4.3 绑定表单参数 #

go
type LoginForm struct {
    Username string `form:"username"`
    Password string `form:"password"`
}

e.POST("/login", func(c echo.Context) error {
    form := new(LoginForm)
    if err := c.Bind(form); err != nil {
        return err
    }
    
    return c.JSON(http.StatusOK, form)
})

五、JSON参数 #

5.1 基本用法 #

go
type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

e.POST("/users", func(c echo.Context) error {
    u := new(User)
    if err := c.Bind(u); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    
    return c.JSON(http.StatusCreated, u)
})

测试:

bash
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","email":"zhangsan@example.com","age":25}' \
  http://localhost:8080/users

5.2 嵌套JSON #

go
type Address struct {
    City    string `json:"city"`
    Country string `json:"country"`
}

type User struct {
    Name    string  `json:"name"`
    Address Address `json:"address"`
}

e.POST("/users", func(c echo.Context) error {
    u := new(User)
    if err := c.Bind(u); err != nil {
        return err
    }
    
    return c.JSON(http.StatusCreated, u)
})

测试:

bash
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","address":{"city":"北京","country":"中国"}}' \
  http://localhost:8080/users

5.3 JSON数组 #

go
e.POST("/users/batch", func(c echo.Context) error {
    var users []User
    if err := c.Bind(&users); err != nil {
        return err
    }
    
    return c.JSON(http.StatusCreated, map[string]int{
        "count": len(users),
    })
})

测试:

bash
curl -X POST \
  -H "Content-Type: application/json" \
  -d '[{"name":"张三"},{"name":"李四"}]' \
  http://localhost:8080/users/batch

六、请求头参数 #

6.1 获取单个请求头 #

go
e.GET("/headers", func(c echo.Context) error {
    auth := c.Request().Header.Get("Authorization")
    contentType := c.Request().Header.Get("Content-Type")
    
    return c.JSON(http.StatusOK, map[string]string{
        "authorization": auth,
        "content-type":  contentType,
    })
})

测试:

bash
curl -H "Authorization: Bearer token123" http://localhost:8080/headers
{"authorization":"Bearer token123","content-type":""}

6.2 获取所有请求头 #

go
e.GET("/headers/all", func(c echo.Context) error {
    headers := make(map[string][]string)
    for key, values := range c.Request().Header {
        headers[key] = values
    }
    
    return c.JSON(http.StatusOK, headers)
})

6.3 常用请求头 #

go
e.GET("/info", func(c echo.Context) error {
    userAgent := c.Request().UserAgent()
    host := c.Request().Host
    referer := c.Request().Header.Get("Referer")
    
    return c.JSON(http.StatusOK, map[string]string{
        "userAgent": userAgent,
        "host":      host,
        "referer":   referer,
    })
})

七、Cookie参数 #

7.1 获取Cookie #

go
e.GET("/cookie", func(c echo.Context) error {
    cookie, err := c.Cookie("session")
    if err != nil {
        return c.String(http.StatusOK, "No cookie")
    }
    
    return c.String(http.StatusOK, "Session: "+cookie.Value)
})

7.2 设置Cookie #

go
e.GET("/set-cookie", func(c echo.Context) error {
    cookie := &http.Cookie{
        Name:     "session",
        Value:    "abc123",
        Path:     "/",
        HttpOnly: true,
        Secure:   true,
        MaxAge:   3600,
    }
    
    c.SetCookie(cookie)
    
    return c.String(http.StatusOK, "Cookie set")
})

7.3 获取所有Cookie #

go
e.GET("/cookies", func(c echo.Context) error {
    cookies := c.Cookies()
    
    result := make(map[string]string)
    for _, cookie := range cookies {
        result[cookie.Name] = cookie.Value
    }
    
    return c.JSON(http.StatusOK, result)
})

八、参数绑定 #

8.1 Bind方法 #

Bind方法自动根据Content-Type绑定数据:

go
type User struct {
    Name  string `json:"name" form:"name" query:"name"`
    Email string `json:"email" form:"email" query:"email"`
}

e.POST("/users", func(c echo.Context) error {
    u := new(User)
    if err := c.Bind(u); err != nil {
        return err
    }
    
    return c.JSON(http.StatusCreated, u)
})

8.2 绑定来源优先级 #

text
1. URL路径参数
2. 查询参数
3. 请求体

8.3 指定绑定来源 #

go
type User struct {
    Name string `query:"name"`
}

e.GET("/users", func(c echo.Context) error {
    u := new(User)
    if err := c.Bind(u); err != nil {
        return err
    }
    
    return c.JSON(http.StatusOK, u)
})

九、参数验证 #

9.1 使用validator #

安装validator:

bash
go get github.com/go-playground/validator/v10

配置验证器:

go
package main

import (
    "net/http"
    "github.com/go-playground/validator/v10"
    "github.com/labstack/echo/v4"
)

type User struct {
    Name  string `json:"name" validate:"required"`
    Email string `json:"email" validate:"required,email"`
    Age   int    `json:"age" validate:"gte=0,lte=130"`
}

type CustomValidator struct {
    validator *validator.Validate
}

func (cv *CustomValidator) Validate(i interface{}) error {
    return cv.validator.Struct(i)
}

func main() {
    e := echo.New()
    e.Validator = &CustomValidator{validator: validator.New()}
    
    e.POST("/users", func(c echo.Context) error {
        u := new(User)
        if err := c.Bind(u); err != nil {
            return err
        }
        if err := c.Validate(u); err != nil {
            return echo.NewHTTPError(http.StatusBadRequest, err.Error())
        }
        
        return c.JSON(http.StatusCreated, u)
    })
    
    e.Start(":8080")
}

9.2 验证标签 #

标签 说明
required 必填
email 邮箱格式
min=x 最小值
max=x 最大值
gte=x 大于等于
lte=x 小于等于
oneof=x y z 枚举值
url URL格式
datetime 日期时间格式

9.3 自定义验证 #

go
func (cv *CustomValidator) Validate(i interface{}) error {
    cv.validator.RegisterValidation("custom", func(fl validator.FieldLevel) bool {
        return fl.Field().String() == "valid"
    })
    return cv.validator.Struct(i)
}

type Data struct {
    Value string `json:"value" validate:"custom"`
}

十、综合示例 #

go
package main

import (
    "net/http"
    "strconv"
    "github.com/go-playground/validator/v10"
    "github.com/labstack/echo/v4"
)

type User struct {
    ID       int    `json:"id" param:"id"`
    Name     string `json:"name" form:"name" query:"name" validate:"required"`
    Email    string `json:"email" form:"email" query:"email" validate:"required,email"`
    Age      int    `json:"age" form:"age" query:"age" validate:"gte=0,lte=130"`
    Password string `json:"password" form:"password" validate:"required,min=6"`
}

type CustomValidator struct {
    validator *validator.Validate
}

func (cv *CustomValidator) Validate(i interface{}) error {
    return cv.validator.Struct(i)
}

func main() {
    e := echo.New()
    e.Validator = &CustomValidator{validator: validator.New()}
    
    e.GET("/users/:id", getUser)
    e.GET("/users", listUsers)
    e.POST("/users", createUser)
    e.POST("/login", login)
    
    e.Start(":8080")
}

func getUser(c echo.Context) error {
    id := c.Param("id")
    
    if _, err := strconv.Atoi(id); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "ID必须是数字")
    }
    
    user := &User{
        ID:    1,
        Name:  "张三",
        Email: "zhangsan@example.com",
        Age:   25,
    }
    
    return c.JSON(http.StatusOK, user)
}

func listUsers(c echo.Context) error {
    page := c.QueryParam("page")
    size := c.QueryParam("size")
    
    users := []*User{
        {ID: 1, Name: "张三", Email: "zhangsan@example.com", Age: 25},
        {ID: 2, Name: "李四", Email: "lisi@example.com", Age: 30},
    }
    
    return c.JSON(http.StatusOK, map[string]interface{}{
        "page":  page,
        "size":  size,
        "users": users,
    })
}

func createUser(c echo.Context) error {
    u := new(User)
    if err := c.Bind(u); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    if err := c.Validate(u); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    
    u.ID = 3
    
    return c.JSON(http.StatusCreated, u)
}

func login(c echo.Context) error {
    u := new(User)
    if err := c.Bind(u); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    if err := c.Validate(u); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    
    return c.JSON(http.StatusOK, map[string]string{
        "token": "jwt-token-here",
    })
}

十一、总结 #

参数获取方法:

方法 用途 示例
Param() 路径参数 c.Param("id")
QueryParam() 查询参数 c.QueryParam("page")
QueryParams() 所有查询参数 c.QueryParams()
FormValue() 表单参数 c.FormValue("name")
Bind() 绑定到结构体 c.Bind(&user)
Cookie() Cookie c.Cookie("session")
Header.Get() 请求头 c.Request().Header.Get("Auth")

准备好学习路由分组了吗?让我们进入下一章!

最后更新:2026-03-28