响应处理 #

一、响应类型概述 #

Echo支持多种响应类型,满足不同的业务需求。

1.1 响应类型 #

方法 说明 Content-Type
String 字符串 text/plain
JSON JSON对象 application/json
JSONP JSONP application/javascript
XML XML application/xml
HTML HTML text/html
File 文件 根据文件类型
Blob 二进制 自定义
Stream 自定义
NoContent 无内容 -

二、字符串响应 #

2.1 基本用法 #

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

2.2 格式化字符串 #

go
e.GET("/user/:id", func(c echo.Context) error {
    id := c.Param("id")
    return c.String(http.StatusOK, fmt.Sprintf("User ID: %s", id))
})

2.3 多行文本 #

go
e.GET("/text", func(c echo.Context) error {
    text := `第一行
第二行
第三行`
    return c.String(http.StatusOK, text)
})

三、JSON响应 #

3.1 基本用法 #

go
e.GET("/json", func(c echo.Context) error {
    return c.JSON(http.StatusOK, map[string]string{
        "message": "Hello",
        "status":  "success",
    })
})

3.2 结构体响应 #

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

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

3.3 数组响应 #

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)
})

3.4 嵌套结构 #

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

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

e.GET("/user/detail", func(c echo.Context) error {
    user := User{
        ID:   1,
        Name: "张三",
        Address: Address{
            City:    "北京",
            Country: "中国",
        },
    }
    return c.JSON(http.StatusOK, user)
})

3.5 标准响应格式 #

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

func Success(c echo.Context, data interface{}) error {
    return c.JSON(http.StatusOK, Response{
        Code:    0,
        Message: "success",
        Data:    data,
    })
}

func Error(c echo.Context, code int, message string) error {
    return c.JSON(code, Response{
        Code:    code,
        Message: message,
    })
}

e.GET("/success", func(c echo.Context) error {
    return Success(c, map[string]string{"name": "张三"})
})

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

3.6 分页响应 #

go
type PageResponse struct {
    Code    int         `json:"code"`
    Message string      `json:"message"`
    Data    interface{} `json:"data"`
    Total   int64       `json:"total"`
    Page    int         `json:"page"`
    Size    int         `json:"size"`
}

func PageSuccess(c echo.Context, data interface{}, total int64, page, size int) error {
    return c.JSON(http.StatusOK, PageResponse{
        Code:    0,
        Message: "success",
        Data:    data,
        Total:   total,
        Page:    page,
        Size:    size,
    })
}

四、JSONP响应 #

4.1 基本用法 #

go
e.GET("/jsonp", func(c echo.Context) error {
    callback := c.QueryParam("callback")
    return c.JSONP(http.StatusOK, callback, map[string]string{
        "message": "Hello",
    })
})

4.2 测试 #

bash
curl "http://localhost:8080/jsonp?callback=myCallback"
myCallback({"message":"Hello"})

五、XML响应 #

5.1 基本用法 #

go
type User struct {
    XMLName xml.Name `xml:"user"`
    ID      int      `xml:"id"`
    Name    string   `xml:"name"`
}

e.GET("/xml", func(c echo.Context) error {
    user := User{
        ID:   1,
        Name: "张三",
    }
    return c.XML(http.StatusOK, user)
})

5.2 响应示例 #

xml
<user>
    <id>1</id>
    <name>张三</name>
</user>

六、HTML响应 #

6.1 基本用法 #

go
e.GET("/html", func(c echo.Context) error {
    return c.HTML(http.StatusOK, "<h1>Hello, World!</h1>")
})

6.2 多行HTML #

go
e.GET("/page", func(c echo.Context) error {
    html := `
    <!DOCTYPE html>
    <html>
    <head>
        <title>My Page</title>
    </head>
    <body>
        <h1>Welcome</h1>
        <p>This is a paragraph.</p>
    </body>
    </html>
    `
    return c.HTML(http.StatusOK, html)
})

6.3 动态HTML #

go
e.GET("/user/:id", func(c echo.Context) error {
    id := c.Param("id")
    html := fmt.Sprintf(`
    <html>
    <body>
        <h1>User Profile</h1>
        <p>User ID: %s</p>
    </body>
    </html>
    `, id)
    return c.HTML(http.StatusOK, html)
})

七、文件响应 #

7.1 返回文件 #

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

7.2 文件下载 #

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

7.3 内联显示 #

go
e.GET("/inline", func(c echo.Context) error {
    return c.Inline("files/document.pdf", "document.pdf")
})

7.4 动态生成文件 #

go
e.GET("/generate", func(c echo.Context) error {
    content := "Hello, World!"
    
    return c.Blob(http.StatusOK, "text/plain", []byte(content))
})

7.5 CSV下载 #

go
e.GET("/csv", func(c echo.Context) error {
    var buf bytes.Buffer
    
    writer := csv.NewWriter(&buf)
    writer.Write([]string{"ID", "Name", "Email"})
    writer.Write([]string{"1", "张三", "zhangsan@example.com"})
    writer.Write([]string{"2", "李四", "lisi@example.com"})
    writer.Flush()
    
    c.Response().Header().Set("Content-Disposition", "attachment; filename=users.csv")
    return c.Blob(http.StatusOK, "text/csv", buf.Bytes())
})

八、二进制响应 #

8.1 Blob响应 #

go
e.GET("/blob", func(c echo.Context) error {
    data := []byte("Hello, World!")
    return c.Blob(http.StatusOK, "text/plain", data)
})

8.2 图片响应 #

go
e.GET("/image", func(c echo.Context) error {
    file, err := os.ReadFile("images/photo.jpg")
    if err != nil {
        return err
    }
    
    return c.Blob(http.StatusOK, "image/jpeg", file)
})

8.3 动态生成图片 #

go
e.GET("/qr", func(c echo.Context) error {
    content := c.QueryParam("content")
    
    img, err := generateQRCode(content)
    if err != nil {
        return err
    }
    
    var buf bytes.Buffer
    png.Encode(&buf, img)
    
    return c.Blob(http.StatusOK, "image/png", buf.Bytes())
})

九、流式响应 #

9.1 Stream响应 #

go
e.GET("/stream", func(c echo.Context) error {
    reader := strings.NewReader("Hello, World!")
    return c.Stream(http.StatusOK, "text/plain", reader)
})

9.2 大文件下载 #

go
e.GET("/large-file", func(c echo.Context) error {
    file, err := os.Open("large-file.zip")
    if err != nil {
        return err
    }
    defer file.Close()
    
    stat, _ := file.Stat()
    
    c.Response().Header().Set("Content-Length", fmt.Sprintf("%d", stat.Size()))
    c.Response().Header().Set("Content-Disposition", "attachment; filename=large-file.zip")
    
    return c.Stream(http.StatusOK, "application/zip", file)
})

9.3 Server-Sent Events #

go
e.GET("/events", func(c echo.Context) error {
    c.Response().Header().Set("Content-Type", "text/event-stream")
    c.Response().Header().Set("Cache-Control", "no-cache")
    c.Response().Header().Set("Connection", "keep-alive")
    
    flusher, ok := c.Response().Writer.(http.Flusher)
    if !ok {
        return echo.NewHTTPError(http.StatusInternalServerError, "Streaming unsupported")
    }
    
    for i := 0; i < 10; i++ {
        fmt.Fprintf(c.Response(), "data: Message %d\n\n", i)
        flusher.Flush()
        time.Sleep(1 * time.Second)
    }
    
    return nil
})

十、重定向 #

10.1 临时重定向 #

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

10.2 永久重定向 #

go
e.GET("/old", func(c echo.Context) error {
    return c.Redirect(http.StatusMovedPermanently, "/new")
})

10.3 外部URL #

go
e.GET("/external", func(c echo.Context) error {
    return c.Redirect(http.StatusFound, "https://example.com")
})

十一、状态码 #

11.1 常用状态码 #

状态码 说明
200 OK
201 Created
204 No Content
301 Moved Permanently
302 Found
304 Not Modified
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
500 Internal Server Error

11.2 无内容响应 #

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

11.3 自定义状态码 #

go
e.GET("/custom", func(c echo.Context) error {
    return c.String(http.StatusCreated, "Created")
})

十二、响应头 #

12.1 设置响应头 #

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

12.2 添加响应头 #

go
e.GET("/add-header", func(c echo.Context) error {
    c.Response().Header().Add("Set-Cookie", "session=abc123")
    c.Response().Header().Add("Set-Cookie", "token=xyz789")
    
    return c.String(http.StatusOK, "OK")
})

12.3 缓存控制 #

go
e.GET("/cached", func(c echo.Context) error {
    c.Response().Header().Set("Cache-Control", "max-age=3600")
    c.Response().Header().Set("ETag", "abc123")
    
    return c.String(http.StatusOK, "Cached content")
})

十三、完整示例 #

go
package main

import (
    "bytes"
    "encoding/csv"
    "fmt"
    "net/http"
    "os"
    "strings"
    "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("/", home)
    e.GET("/json", jsonExample)
    e.GET("/xml", xmlExample)
    e.GET("/html", htmlExample)
    e.GET("/download", downloadFile)
    e.GET("/csv", downloadCSV)
    e.GET("/events", serverSentEvents)
    e.GET("/redirect", redirectExample)
    e.DELETE("/users/:id", deleteUser)
    
    e.Logger.Fatal(e.Start(":8080"))
}

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

func jsonExample(c echo.Context) error {
    return c.JSON(http.StatusOK, Response{
        Code:    0,
        Message: "success",
        Data: map[string]string{
            "name": "张三",
            "email": "zhangsan@example.com",
        },
    })
}

func xmlExample(c echo.Context) error {
    type User struct {
        XMLName xml.Name `xml:"user"`
        Name    string   `xml:"name"`
        Email   string   `xml:"email"`
    }
    
    user := User{
        Name:  "张三",
        Email: "zhangsan@example.com",
    }
    
    return c.XML(http.StatusOK, user)
}

func htmlExample(c echo.Context) error {
    html := `
    <!DOCTYPE html>
    <html>
    <head><title>My Page</title></head>
    <body><h1>Hello, World!</h1></body>
    </html>
    `
    return c.HTML(http.StatusOK, html)
}

func downloadFile(c echo.Context) error {
    return c.Attachment("files/report.pdf", "report.pdf")
}

func downloadCSV(c echo.Context) error {
    var buf bytes.Buffer
    
    writer := csv.NewWriter(&buf)
    writer.Write([]string{"ID", "Name", "Email"})
    writer.Write([]string{"1", "张三", "zhangsan@example.com"})
    writer.Write([]string{"2", "李四", "lisi@example.com"})
    writer.Flush()
    
    c.Response().Header().Set("Content-Disposition", "attachment; filename=users.csv")
    return c.Blob(http.StatusOK, "text/csv", buf.Bytes())
}

func serverSentEvents(c echo.Context) error {
    c.Response().Header().Set("Content-Type", "text/event-stream")
    c.Response().Header().Set("Cache-Control", "no-cache")
    c.Response().Header().Set("Connection", "keep-alive")
    
    flusher, ok := c.Response().Writer.(http.Flusher)
    if !ok {
        return echo.NewHTTPError(http.StatusInternalServerError, "Streaming unsupported")
    }
    
    for i := 0; i < 5; i++ {
        fmt.Fprintf(c.Response(), "data: Message %d\n\n", i)
        flusher.Flush()
        time.Sleep(1 * time.Second)
    }
    
    return nil
}

func redirectExample(c echo.Context) error {
    return c.Redirect(http.StatusFound, "/")
}

func deleteUser(c echo.Context) error {
    id := c.Param("id")
    fmt.Printf("Deleting user %s\n", id)
    return c.NoContent(http.StatusNoContent)
}

十四、总结 #

响应方法要点:

方法 用途 示例
String 字符串 c.String(200, "text")
JSON JSON c.JSON(200, data)
JSONP JSONP c.JSONP(200, "callback", data)
XML XML c.XML(200, data)
HTML HTML c.HTML(200, "<h1>...</h1>")
File 文件 c.File("path")
Attachment 下载 c.Attachment("path", "name")
Blob 二进制 c.Blob(200, "type", data)
Stream c.Stream(200, "type", reader)
NoContent 无内容 c.NoContent(204)
Redirect 重定向 c.Redirect(302, "/path")

准备好学习数据绑定与验证了吗?让我们进入下一章!

最后更新:2026-03-28