これはベスト プラクティスの質問であり、正解はおそらく 1 つではありません。私のハンドラーのほとんどは、ハンドラーに固有の作業を開始する前に、多くの一般的な初期化ジョブを実行する必要があるようです。例としては、ユーザー認証、ロケールの検出と翻訳された文字列の読み込み、memcached 値のチェックなどがあります。
これらのタスクの一部は 内で処理するのが合理的と思われますinit
が、ほとんどの場合、Http.Request
またはが必要ですappengine.Context
。私が見る限り、これには 3 つの選択肢があります。
ServeHTTP
最後にカスタム init 関数を実行する機能を実装して追加します。問題は、独自の を実装する Gorilla mux を使用できないことServeHTTP
です。フォークされたバージョンの mux を使用します (理想的とは言えません)。
startHandler
アプリ全体のすべてのハンドラーの先頭に関数を配置します。面倒なように思えますが、一般的なコードを「隠す」のではなく、何が起こっているのかを正確に理解できると思いますServeHTTP
。
すべてのハンドラーに共通のジョブを処理するための推奨される方法は何ですか? 別のアプローチがありませんか?
これは、ミニコミの回答で概説されているアプローチの完全な App Engine の例です。また、 Jeff Wendling のチュートリアルも参照する価値があります。
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.