第一个应用 #

一、创建项目 #

1.1 项目初始化 #

bash
mkdir hello-echo
cd hello-echo
go mod init hello-echo
go get github.com/labstack/echo/v4

1.2 项目结构 #

text
hello-echo/
├── main.go
├── go.mod
└── go.sum

二、Hello World #

2.1 最简示例 #

创建 main.go

go
package main

import (
    "net/http"
    "github.com/labstack/echo/v4"
)

func main() {
    e := echo.New()
    
    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, World!")
    })
    
    e.Start(":8080")
}

2.2 运行应用 #

bash
go run main.go

输出:

text
   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.11.1
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8080

2.3 测试访问 #

bash
curl http://localhost:8080
Hello, World!

三、代码解析 #

3.1 创建Echo实例 #

go
e := echo.New()

创建一个Echo应用实例,这是所有功能的入口点。

3.2 定义路由 #

go
e.GET("/", func(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
})
部分 说明
e.GET 注册GET路由
"/" 路由路径
func(c echo.Context) error 处理函数
c.String() 返回字符串响应
http.StatusOK HTTP状态码200

3.3 启动服务器 #

go
e.Start(":8080")

在8080端口启动HTTP服务器。

四、多种响应类型 #

4.1 JSON响应 #

go
package main

import (
    "net/http"
    "github.com/labstack/echo/v4"
)

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

func main() {
    e := echo.New()
    
    e.GET("/json", func(c echo.Context) error {
        user := User{
            ID:   1,
            Name: "张三",
        }
        return c.JSON(http.StatusOK, user)
    })
    
    e.Start(":8080")
}

测试:

bash
curl http://localhost:8080/json
{"id":1,"name":"张三"}

4.2 JSON数组响应 #

go
e.GET("/users", func(c echo.Context) error {
    users := []User{
        {ID: 1, Name: "张三"},
        {ID: 2, Name: "李四"},
        {ID: 3, Name: "王五"},
    }
    return c.JSON(http.StatusOK, users)
})

4.3 HTML响应 #

go
e.GET("/html", func(c echo.Context) error {
    html := `<html>
        <head><title>Hello</title></head>
        <body><h1>Hello, Echo!</h1></body>
    </html>`
    return c.HTML(http.StatusOK, html)
})

4.4 文件响应 #

go
e.GET("/file", func(c echo.Context) error {
    return c.File("static/hello.txt")
})

4.5 附件下载 #

go
e.GET("/download", func(c echo.Context) error {
    return c.Attachment("files/report.pdf", "report.pdf")
})

4.6 重定向 #

go
e.GET("/redirect", func(c echo.Context) error {
    return c.Redirect(http.StatusFound, "/json")
})

4.7 无内容响应 #

go
e.DELETE("/users/:id", func(c echo.Context) error {
    return c.NoContent(http.StatusNoContent)
})

五、多路由示例 #

5.1 完整示例 #

go
package main

import (
    "net/http"
    "github.com/labstack/echo/v4"
)

func main() {
    e := echo.New()
    
    e.GET("/", home)
    e.GET("/users", getUsers)
    e.GET("/users/:id", getUser)
    e.POST("/users", createUser)
    e.PUT("/users/:id", updateUser)
    e.DELETE("/users/:id", deleteUser)
    
    e.Start(":8080")
}

func home(c echo.Context) error {
    return c.String(http.StatusOK, "Welcome to Echo!")
}

func getUsers(c echo.Context) error {
    return c.JSON(http.StatusOK, []map[string]interface{}{
        {"id": 1, "name": "张三"},
        {"id": 2, "name": "李四"},
    })
}

func getUser(c echo.Context) error {
    id := c.Param("id")
    return c.JSON(http.StatusOK, map[string]string{
        "id":   id,
        "name": "用户" + id,
    })
}

func createUser(c echo.Context) error {
    type User struct {
        Name string `json:"name"`
    }
    u := new(User)
    if err := c.Bind(u); err != nil {
        return err
    }
    return c.JSON(http.StatusCreated, map[string]string{
        "id":   "3",
        "name": u.Name,
    })
}

func updateUser(c echo.Context) error {
    id := c.Param("id")
    type User struct {
        Name string `json:"name"`
    }
    u := new(User)
    if err := c.Bind(u); err != nil {
        return err
    }
    return c.JSON(http.StatusOK, map[string]string{
        "id":   id,
        "name": u.Name,
    })
}

func deleteUser(c echo.Context) error {
    return c.NoContent(http.StatusNoContent)
}

5.2 测试API #

bash
curl http://localhost:8080/
curl http://localhost:8080/users
curl http://localhost:8080/users/1
curl -X POST -H "Content-Type: application/json" -d '{"name":"王五"}' http://localhost:8080/users
curl -X PUT -H "Content-Type: application/json" -d '{"name":"赵六"}' http://localhost:8080/users/1
curl -X DELETE http://localhost:8080/users/1

六、处理函数 #

6.1 匿名函数 #

go
e.GET("/", func(c echo.Context) error {
    return c.String(http.StatusOK, "Hello")
})

6.2 命名函数 #

go
func hello(c echo.Context) error {
    return c.String(http.StatusOK, "Hello")
}

e.GET("/", hello)

6.3 方法绑定 #

go
type Handler struct{}

func (h *Handler) Hello(c echo.Context) error {
    return c.String(http.StatusOK, "Hello")
}

func main() {
    e := echo.New()
    h := &Handler{}
    e.GET("/", h.Hello)
    e.Start(":8080")
}

6.4 函数返回 #

go
func helloHandler(msg string) echo.HandlerFunc {
    return func(c echo.Context) error {
        return c.String(http.StatusOK, msg)
    }
}

e.GET("/", helloHandler("Hello"))
e.GET("/hi", helloHandler("Hi"))

七、路由参数 #

7.1 路径参数 #

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

7.2 查询参数 #

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

测试:

bash
curl "http://localhost:8080/search?q=echo&page=1"
Search: echo, Page: 1

7.3 表单参数 #

go
e.POST("/login", func(c echo.Context) error {
    username := c.FormValue("username")
    password := c.FormValue("password")
    return c.String(http.StatusOK, "Login: "+username)
})

测试:

bash
curl -X POST -d "username=admin&password=123456" http://localhost:8080/login
Login: admin

八、请求头处理 #

8.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,
    })
})

8.2 设置响应头 #

go
e.GET("/custom-header", func(c echo.Context) error {
    c.Response().Header().Set("X-Custom-Header", "value")
    return c.String(http.StatusOK, "OK")
})

九、错误处理 #

9.1 返回错误 #

go
e.GET("/error", func(c echo.Context) error {
    return echo.NewHTTPError(http.StatusBadRequest, "参数错误")
})

9.2 自定义错误页面 #

go
e.HTTPErrorHandler = func(err error, c echo.Context) {
    code := http.StatusInternalServerError
    if he, ok := err.(*echo.HTTPError); ok {
        code = he.Code
    }
    c.HTML(code, fmt.Sprintf("<h1>Error %d</h1>", code))
}

十、优雅关闭 #

10.1 使用信号 #

go
package main

import (
    "context"
    "net/http"
    "os"
    "os/signal"
    "time"
    "github.com/labstack/echo/v4"
)

func main() {
    e := echo.New()
    
    e.GET("/", func(c echo.Context) error {
        return c.String(http.StatusOK, "Hello, World!")
    })
    
    go func() {
        if err := e.Start(":8080"); err != nil && err != http.ErrServerClosed {
            e.Logger.Fatal("shutting down the server")
        }
    }()
    
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)
    <-quit
    
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    if err := e.Shutdown(ctx); err != nil {
        e.Logger.Fatal(err)
    }
}

10.2 关闭流程 #

text
1. 收到中断信号 (Ctrl+C)
2. 停止接受新请求
3. 等待现有请求完成
4. 关闭服务器

十一、完整示例 #

go
package main

import (
    "context"
    "net/http"
    "os"
    "os/signal"
    "time"
    "github.com/labstack/echo/v4"
)

type Response struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data,omitempty"`
}

func main() {
    e := echo.New()
    
    e.GET("/", func(c echo.Context) error {
        return c.JSON(http.StatusOK, Response{
            Code:    0,
            Message: "success",
            Data:    "Hello, Echo!",
        })
    })
    
    e.GET("/health", func(c echo.Context) error {
        return c.JSON(http.StatusOK, Response{
            Code:    0,
            Message: "healthy",
        })
    })
    
    go func() {
        if err := e.Start(":8080"); err != nil && err != http.ErrServerClosed {
            e.Logger.Fatal("shutting down the server")
        }
    }()
    
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, os.Interrupt)
    <-quit
    
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()
    
    if err := e.Shutdown(ctx); err != nil {
        e.Logger.Fatal(err)
    }
}

十二、总结 #

第一个应用要点:

概念 说明
Echo实例 echo.New() 创建应用
路由 e.GET/POST/PUT/DELETE 注册路由
Context 封装请求和响应
响应类型 JSON、HTML、String、File等
参数获取 Param、QueryParam、FormValue
优雅关闭 监听信号,调用Shutdown

准备好学习应用结构了吗?让我们进入下一章!

最后更新:2026-03-28