您正在描述上下文。
最初是 gorilla context package,它提供了一个伪全局上下文对象 - 本质上是一个 map[interface{}]interface{},其引用本质上可供中间件/控制器/数据层堆栈中的所有参与者使用。
除了an excellent guide to the package 之外,请查看此内容(所有内容均归功于作者,Matt Silverlock)。
type contextKey int
// Define keys that support equality.
const csrfKey contextKey = 0
const userKey contextKey = 1
var ErrCSRFTokenNotPresent = errors.New("CSRF token not present in the request context.")
// We'll need a helper function like this for every key:type
// combination we store in our context map else we repeat this
// in every middleware/handler that needs to access the value.
func GetCSRFToken(r *http.Request) (string, error) {
val, ok := context.GetOk(r, csrfKey)
if !ok {
return "", ErrCSRFTokenNotPresent
}
token, ok := val.(string)
if !ok {
return "", ErrCSRFTokenNotPresent
}
return token, nil
}
// A bare-bones example
func CSRFMiddleware(h http.Handler) http.Handler {
return func(w http.ResponseWriter, r *http.Request) {
token, err := GetCSRFToken(r)
if err != nil {
http.Error(w, "No good!", http.StatusInternalServerError)
return
}
// The map is global, so we just call the Set function
context.Set(r, csrfKey, token)
h.ServeHTTP(w, r)
}
}
在 gorilla 包开始后,context package 被添加到标准库中。它略有不同,因为上下文不再是伪全局的,而是从一个方法传递到另一个方法。在此情况下,上下文附加到初始请求 - 可通过 request.Context 获得。处理程序下方的层可以接受上下文值作为其签名的一部分,并从中读取值。
这是一个简化的例子:
type contextKey string
var (
aPreSharedKey = contextKey("a-preshared-key")
)
func someHandler(w http.ResponseWriter, req *http.Request) {
ctx := context.WithValue(req.Context, aPreSharedKey, req.Header.Get("required-header"))
data, err := someDataLayerFunction(ctx)
if err != nil {
fmt.Fprintf(w, "uhoh", http.StatusBadRequest)
return
}
fmt.Fprintf(w, data, http.StatusOK)
}
func someDataLayerFunction(ctx context.Context) (string, error) {
val, ok := ctx.Value(aPreSharedKey).(string)
if !ok {
return nil, errors.New("required context value missing")
}
return val
}
有关更多详细信息和不那么做作的示例,请查看 google 的 excellent blog on the context package's use.