vah*_*det 3 go go-echo go-context
我正在使用Echo 框架,并希望在设置一些自定义值后传递 Go 内置的底层context.Context echo.Context。
为了实现它,我想我可以首先应用 的Set(key string, val interface{})方法echo.Context,然后提取底层的context.Context.
问题是可以这样做吗?换句话说,是否像echo.Context.Set(...)直接设置值一样?或者我应该采取额外的步骤来复制我的自定义条目。context.ContextWithValue
PS我不想传递echo.Context到我的应用程序的更深层次,这就是为什么我不想直接使用它但得到引用context.Context
方法一:重新实现echo.Context.Get和echo.Context.Set方法来操作ctx.Request().Context()对象。
缺点:每个Set方法都会调用一次http.Request.WithContext,*http.Request会被复制一次。详细信息请参见WithContext方法的实现。
方法二:重新实现echo.Context.Get和echo.Context.Set方法来操作contextValueData2对象,并将http.Request.WithContext设置为自定义的context.Context contextValueData2。
缺点:在go1.13之前,context.Context需要类型断言。不要实现 context.Context 方法。与方法1相比,实现只需要一次WithContext。
推荐使用方法1,清晰简单,方法2比较复杂,没有经过充分测试。
示例导入包使用了gopath,该功能的实现也体现了echo.Context作为接口的优势。
package main
import (
"context"
"fmt"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"net/http"
)
func main() {
// Echo instance
e := echo.New()
// Middleware
e.Use(NewMiddlewareContextValue)
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.GET("/", hello)
e.GET("/val", getval)
// Start server
e.Logger.Fatal(e.Start(":1323"))
}
// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
func getval(c echo.Context) error {
c.Set("111", "aa")
c.Set("222", "bb")
return c.String(http.StatusOK, fmt.Sprint(c.Request().Context()))
}
// ---------- method1 ----------
func NewMiddlewareContextValue(fn echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
return fn(contextValue{ctx})
}
}
type contextValue struct {
echo.Context
}
// Get retrieves data from the context.
func (ctx contextValue) Get(key string) interface{} {
// get old context value
val := ctx.Context.Get(key)
if val != nil {
return val
}
return ctx.Request().Context().Value(key)
}
// Set saves data in the context.
func (ctx contextValue) Set(key string, val interface{}) {
ctx.SetRequest(ctx.Request().WithContext(context.WithValue(ctx.Request().Context(), key, val)))
}
// ---------- method2 ----------
func NewMiddlewareContextValue2(fn echo.HandlerFunc) echo.HandlerFunc {
return func(ctx echo.Context) error {
ctxdata := contextValueData2{
Context: ctx.Request().Context(),
}
ctx.SetRequest(ctx.Request().WithContext(ctxdata))
return fn(&contextValue2{Context: ctx, contextValueData2: ctxdata})
}
}
type contextValue2 struct {
echo.Context
contextValueData2
}
type contextValueData2 struct {
context.Context
Data map[string]interface{}
}
// Get retrieves data from the context.
func (ctx *contextValue2) Get(key string) interface{} {
// get old context value
val := ctx.Context.Get(key)
if val != nil {
return val
}
// get my data value
val, ok := ctx.contextValueData2.Data[key]
if ok {
return val
}
return ctx.contextValueData2.Context.Value(key)
}
// Set saves data in the context.
func (ctx *contextValue2) Set(key string, val interface{}) {
if ctx.Data == nil {
ctx.contextValueData2.Data = make(map[string]interface{})
}
ctx.contextValueData2.Data[key] = val
}
func (ctx contextValueData2) Value(key interface{}) interface{} {
str, ok := key.(string)
if ok {
val, ok := ctx.Data[str]
if ok {
return val
}
}
return ctx.Context.Value(key)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6839 次 |
| 最近记录: |