这是一个最佳实践问题,可能没有一个正确的答案。在开始特定于处理程序的工作之前,我的大多数处理程序似乎需要执行许多常见的初始化作业。示例包括用户身份验证,检测语言环境和加载已翻译的字符串,检查memcached值等。
在init
中处理其中一些任务似乎是合理的,但大多数都需要Http.Request
或appengine.Context
。据我所知,这有三个选择:
实现ServeHTTP
并添加在最后执行自定义初始化函数的功能。问题在于,我无法使用实现自己的ServeHTTP
的Gorilla mux。
使用分叉版本的mux(不太理想)。
在整个应用程序的每个处理程序的开头放置一个startHandler
函数。看起来很麻烦,虽然我认为它确切地说明了正在发生的事情而不是“隐藏”ServeHTTP
中的公共代码。
处理所有处理程序通用的工作的首选方法是什么?我错过了另一种方法吗?
这是minikomi答案中概述的方法的完整App Engine示例。这也值得访问Jeff Wendling's tutorial。
package app
import (
"fmt"
"log"
"net/http"
"appengine"
"appengine/datastore"
"github.com/gorilla/context"
"github.com/gorilla/mux"
)
type Config struct {
DefaultLocale string
DefaultTimezone string
}
type ContextKey int
const (
SiteConfig ContextKey = iota
// ...
)
type InitHandler func(http.ResponseWriter, *http.Request, appengine.Context)
func (h InitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// All handler initialisation tasks go here
c := appengine.NewContext(r)
k := datastore.NewKey(c, "Config", "site:config", 0, nil)
config := new(Config)
if err := datastore.Get(c, k, config); err != nil {
log.Fatal("Couldn't read config from datastore: %s\n", err.Error())
}
context.Set(r, SiteConfig, config)
// Finally, call the handler itself
h(w, r, c)
}
func init () {
r := mux.NewRouter()
r.Handle("/", InitHandler(home)) // Note: NOT r.HandleFunc!
http.Handle("/", r)
}
func home(w http.ResponseWriter, r *http.Request, c appengine.Context) {
site := context.Get(r, SiteConfig).(*Config)
fmt.Fprintf(w, "Locale: %s, timezone: %s.", site.DefaultLocale, site.DefaultTimezone)
}
让我感到遗憾的是需要使用router.Handle
而不是router.HandleFunc
。假设数据存储区中有适当的实体,输出如下:
Locale: en_US, timezone: UTC.
答案 0 :(得分:8)
您可以创建一个(func)类型,其中ServeHTTP
可以执行您需要的所有操作,然后在内部调用原始函数,然后将处理程序转换为该类型:
package main
import (
"fmt"
"log"
"net/http"
)
type wrappedHandler func(w http.ResponseWriter, r *http.Request)
func (h wrappedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println("Do Other GAE Stuff")
h(w, r)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi!")
}
func main() {
http.Handle("/", wrappedHandler(handler))
http.ListenAndServe(":8080", nil)
}
如果您想将某些内容传递给handler()
func,可以将其添加到签名中,例如:
type wrappedHandler func(w http.ResponseWriter, r *http.Request, conn *db.Connection)
func (h wrappedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
conn := db.CreateConnection();
h(w, r, conn)
}
func handler(w http.ResponseWriter, r *http.Request, conn *db.Connection) {
data := conn.AllTheData()
fmt.Fprintf(w, data)
}