【发布时间】:2012-12-30 05:58:38
【问题描述】:
这是一个最佳实践问题,可能没有一个正确答案。似乎我的大多数处理程序都需要在开始处理特定于处理程序的工作之前执行一些常见的初始化作业。例如用户身份验证、检测语言环境和加载翻译后的字符串、检查 memcached 值等等。
在init 中处理其中一些任务似乎是合理的,但大多数需要Http.Request 或appengine.Context。据我所知,这留下了三个选择:
实现
ServeHTTP并在末尾添加执行自定义初始化函数的功能。问题是,我无法使用实现自己的ServeHTTP的 Gorilla 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.
【问题讨论】:
标签: google-app-engine go