请求处理 #
一、请求对象 #
1.1 获取Request #
go
e.GET("/", func(c echo.Context) error {
req := c.Request()
return c.JSON(http.StatusOK, map[string]string{
"method": req.Method,
"host": req.Host,
"url": req.URL.String(),
})
})
1.2 Request常用属性 #
| 属性 | 说明 |
|---|---|
| Method | HTTP方法 |
| URL | 请求URL |
| Header | 请求头 |
| Body | 请求体 |
| ContentLength | 内容长度 |
| Host | 主机名 |
| RemoteAddr | 远程地址 |
二、路径参数 #
2.1 单个参数 #
go
e.GET("/users/:id", func(c echo.Context) error {
id := c.Param("id")
return c.String(http.StatusOK, "User ID: "+id)
})
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,
})
})
2.3 通配符参数 #
go
e.GET("/files/*", func(c echo.Context) error {
path := c.Param("*")
return c.String(http.StatusOK, "File: "+path)
})
三、查询参数 #
3.1 单个参数 #
go
e.GET("/search", func(c echo.Context) error {
q := c.QueryParam("q")
return c.String(http.StatusOK, "Search: "+q)
})
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,
})
})
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 所有查询参数 #
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)
})
3.5 绑定查询参数 #
go
type QueryParams struct {
Page int `query:"page"`
Size int `query:"size"`
Keyword string `query:"keyword"`
}
e.GET("/users", func(c echo.Context) error {
q := new(QueryParams)
if err := c.Bind(q); err != nil {
return err
}
return c.JSON(http.StatusOK, q)
})
四、请求头 #
4.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,
})
})
4.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)
})
4.3 常用请求头 #
go
e.GET("/info", func(c echo.Context) error {
userAgent := c.Request().UserAgent()
referer := c.Request().Header.Get("Referer")
accept := c.Request().Header.Get("Accept")
acceptLanguage := c.Request().Header.Get("Accept-Language")
return c.JSON(http.StatusOK, map[string]string{
"userAgent": userAgent,
"referer": referer,
"accept": accept,
"acceptLanguage": acceptLanguage,
})
})
五、请求体 #
5.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,
})
})
5.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,
})
})
5.3 JSON数据 #
go
type User struct {
Name string `json:"name"`
Email string `json:"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)
})
5.4 读取原始请求体 #
go
e.POST("/raw", func(c echo.Context) error {
body, err := io.ReadAll(c.Request().Body)
if err != nil {
return err
}
return c.String(http.StatusOK, string(body))
})
5.5 XML数据 #
go
type User struct {
XMLName xml.Name `xml:"user"`
Name string `xml:"name"`
Email string `xml:"email"`
}
e.POST("/xml", func(c echo.Context) error {
u := new(User)
if err := xml.NewDecoder(c.Request().Body).Decode(u); err != nil {
return err
}
return c.XML(http.StatusCreated, u)
})
六、文件上传 #
6.1 单文件上传 #
go
e.POST("/upload", func(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return err
}
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
dst, err := os.Create("uploads/" + file.Filename)
if err != nil {
return err
}
defer dst.Close()
if _, err = io.Copy(dst, src); err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]string{
"filename": file.Filename,
"size": fmt.Sprintf("%d", file.Size),
})
})
6.2 多文件上传 #
go
e.POST("/uploads", func(c echo.Context) error {
form, err := c.MultipartForm()
if err != nil {
return err
}
files := form.File["files"]
for _, file := range files {
src, err := file.Open()
if err != nil {
return err
}
dst, err := os.Create("uploads/" + file.Filename)
if err != nil {
src.Close()
return err
}
io.Copy(dst, src)
src.Close()
dst.Close()
}
return c.JSON(http.StatusOK, map[string]int{
"count": len(files),
})
})
6.3 文件信息 #
go
e.POST("/file-info", func(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]interface{}{
"filename": file.Filename,
"size": file.Size,
"header": file.Header,
})
})
七、数据绑定 #
7.1 Bind方法 #
go
type User struct {
Name string `json:"name" form:"name" query:"name" param:"name"`
Email string `json:"email" form:"email" query:"email"`
Age int `json:"age" form:"age" query:"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)
})
7.2 绑定来源 #
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)
})
7.3 绑定优先级 #
text
1. URL路径参数 (param)
2. 查询参数 (query)
3. 请求体 (json/form)
八、请求验证 #
8.1 使用validator #
go
type User struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=6"`
Age int `json:"age" validate:"gte=0,lte=130"`
}
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)
})
8.2 验证标签 #
| 标签 | 说明 |
|---|---|
| required | 必填 |
| 邮箱格式 | |
| min | 最小值 |
| max | 最大值 |
| gte | 大于等于 |
| lte | 小于等于 |
| oneof | 枚举值 |
| url | URL格式 |
九、客户端信息 #
9.1 IP地址 #
go
e.GET("/ip", func(c echo.Context) error {
realIP := c.RealIP()
remoteAddr := c.Request().RemoteAddr
return c.JSON(http.StatusOK, map[string]string{
"realIP": realIP,
"remoteAddr": remoteAddr,
})
})
9.2 协议信息 #
go
e.GET("/protocol", func(c echo.Context) error {
scheme := c.Scheme()
isTLS := c.IsTLS()
proto := c.Request().Proto
return c.JSON(http.StatusOK, map[string]interface{}{
"scheme": scheme,
"isTLS": isTLS,
"proto": proto,
})
})
十、完整示例 #
go
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
"github.com/go-playground/validator/v10"
"github.com/labstack/echo/v4"
)
type User struct {
ID int `json:"id"`
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Password string `json:"password" validate:"required,min=6"`
Age int `json:"age" validate:"gte=0,lte=130"`
}
type QueryParams struct {
Page int `query:"page"`
Size int `query:"size"`
Keyword string `query:"keyword"`
}
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("/", home)
e.GET("/users", listUsers)
e.GET("/users/:id", getUser)
e.POST("/users", createUser)
e.PUT("/users/:id", updateUser)
e.POST("/upload", uploadFile)
e.GET("/info", getInfo)
e.Logger.Fatal(e.Start(":8080"))
}
func home(c echo.Context) error {
return c.String(http.StatusOK, "Welcome!")
}
func listUsers(c echo.Context) error {
q := new(QueryParams)
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, map[string]interface{}{
"page": q.Page,
"size": q.Size,
"keyword": q.Keyword,
"users": []map[string]string{
{"id": "1", "name": "张三"},
{"id": "2", "name": "李四"},
},
})
}
func getUser(c echo.Context) error {
id := c.Param("id")
if _, err := strconv.Atoi(id); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "ID必须是数字")
}
return c.JSON(http.StatusOK, map[string]string{
"id": id,
"name": "用户" + id,
})
}
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 = 1
return c.JSON(http.StatusCreated, u)
}
func updateUser(c echo.Context) error {
id := c.Param("id")
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())
}
u.ID, _ = strconv.Atoi(id)
return c.JSON(http.StatusOK, u)
}
func uploadFile(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return err
}
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
os.MkdirAll("uploads", 0755)
dst, err := os.Create("uploads/" + file.Filename)
if err != nil {
return err
}
defer dst.Close()
if _, err = io.Copy(dst, src); err != nil {
return err
}
return c.JSON(http.StatusOK, map[string]string{
"filename": file.Filename,
"size": fmt.Sprintf("%d", file.Size),
"message": "上传成功",
})
}
func getInfo(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]interface{}{
"method": c.Request().Method,
"path": c.Path(),
"realIP": c.RealIP(),
"scheme": c.Scheme(),
"isTLS": c.IsTLS(),
"userAgent": c.Request().UserAgent(),
"headers": c.Request().Header,
})
}
十一、总结 #
请求处理方法:
| 方法 | 用途 |
|---|---|
Param() |
路径参数 |
QueryParam() |
查询参数 |
QueryParams() |
所有查询参数 |
FormValue() |
表单参数 |
FormFile() |
上传文件 |
MultipartForm() |
多文件表单 |
Bind() |
数据绑定 |
Validate() |
数据验证 |
Request() |
请求对象 |
RealIP() |
客户端IP |
准备好学习响应处理了吗?让我们进入下一章!
最后更新:2026-03-28