在 Echo 框架中,echo.Context 是请求级别的上下文,无法在不同 HTTP 请求间共享数据。每个请求都有独立的上下文实例。
要在不同请求间传递数据,可以使用以下方法:
1. 使用中间件设置全局数据
通过自定义中间件将数据注入到每个请求的上下文中:
package main
import (
"github.com/labstack/echo/v4"
"net/http"
)
type SharedData struct {
UserID string
AppToken string
}
func main() {
e := echo.New()
// 全局中间件 - 为每个请求设置共享数据
e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// 这里可以从数据库、缓存或配置中获取数据
shared := &SharedData{
UserID: "global-user-123",
AppToken: "token-xyz",
}
c.Set("shared_data", shared)
return next(c)
}
})
e.GET("/first", func(c echo.Context) error {
// 获取共享数据
if data, ok := c.Get("shared_data").(*SharedData); ok {
return c.JSON(http.StatusOK, map[string]interface{}{
"user_id": data.UserID,
"message": "First request",
})
}
return c.String(http.StatusInternalServerError, "Data not found")
})
e.GET("/second", func(c echo.Context) error {
// 在另一个请求中访问相同的数据
if data, ok := c.Get("shared_data").(*SharedData); ok {
return c.JSON(http.StatusOK, map[string]interface{}{
"token": data.AppToken,
"message": "Second request",
})
}
return c.String(http.StatusInternalServerError, "Data not found")
})
e.Start(":8080")
}
2. 使用外部存储(Redis/数据库)
对于需要在不同请求间持久化的数据:
package main
import (
"context"
"github.com/go-redis/redis/v8"
"github.com/labstack/echo/v4"
"net/http"
"time"
)
var rdb *redis.Client
var ctx = context.Background()
func main() {
// 初始化 Redis 客户端
rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
e := echo.New()
e.POST("/set-data", func(c echo.Context) error {
key := c.QueryParam("key")
value := c.QueryParam("value")
// 将数据存储到 Redis
err := rdb.Set(ctx, key, value, 10*time.Minute).Err()
if err != nil {
return c.String(http.StatusInternalServerError, err.Error())
}
return c.JSON(http.StatusOK, map[string]string{
"status": "data stored",
"key": key,
})
})
e.GET("/get-data", func(c echo.Context) error {
key := c.QueryParam("key")
// 从 Redis 获取数据
value, err := rdb.Get(ctx, key).Result()
if err != nil {
return c.String(http.StatusNotFound, "Data not found")
}
return c.JSON(http.StatusOK, map[string]string{
"key": key,
"value": value,
})
})
e.Start(":8080")
}
3. 使用全局变量(谨慎使用)
对于只读的全局配置数据:
package main
import (
"github.com/labstack/echo/v4"
"net/http"
"sync"
)
type AppConfig struct {
Version string
Env string
}
var (
appConfig *AppConfig
configOnce sync.Once
)
func getConfig() *AppConfig {
configOnce.Do(func() {
appConfig = &AppConfig{
Version: "1.0.0",
Env: "production",
}
})
return appConfig
}
func main() {
e := echo.New()
e.GET("/config", func(c echo.Context) error {
config := getConfig()
return c.JSON(http.StatusOK, config)
})
e.GET("/info", func(c echo.Context) error {
config := getConfig()
return c.JSON(http.StatusOK, map[string]string{
"version": config.Version,
"env": config.Env,
})
})
e.Start(":8080")
}
4. 使用请求参数传递数据
通过 URL 参数、查询字符串或请求头传递:
package main
import (
"github.com/labstack/echo/v4"
"net/http"
)
func main() {
e := echo.New()
// 第一个请求设置数据并重定向
e.GET("/set-and-redirect", func(c echo.Context) error {
data := c.QueryParam("data")
// 将数据编码在 URL 中传递
return c.Redirect(http.StatusFound, "/process?data="+data)
})
// 第二个请求接收数据
e.GET("/process", func(c echo.Context) error {
data := c.QueryParam("data")
return c.JSON(http.StatusOK, map[string]string{
"received_data": data,
})
})
e.Start(":8080")
}
echo.Context.Set() 和 echo.Context.Get() 方法只在当前请求的生命周期内有效。对于跨请求的数据共享,需要使用中间件注入全局数据、外部存储系统或请求参数传递。