2013-01-16 7 views
7

これはおそらく1つの正解がないベストプラクティスの質問です。私のハンドラのほとんどは、ハンドラに固有の作業を開始する前に、多くの一般的な初期化ジョブを実行する必要があるようです。例としては、ユーザーの認証、ロケールの検出、翻訳された文字列のロード、memcached値のチェックなどがあります。Goを使用して一般的なApp Engineハンドラタスクを達成する

これらのタスクの一部をinitで処理するのが妥当と思われますが、ほとんどの場合、Http.Requestまたはappengine.Contextが必要です。

  1. ServeHTTPを実装し、最後にカスタムのinit関数を実行する能力を追加します。私の知る限り見ることができるように、これは3つの選択肢を残します。問題は、自分で実装したGorillaマルチプレクサを使用することができないということですServeHTTP

  2. muxのフォークバージョンを使用してください(理想的ではありません)。

  3. 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. 

答えて

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) 
} 
+1

私が最初に私が考えましたこの方法でゴリラmuxを使用することができなかった、その後、私はキャストに気づいた!ニース。このチュートリアルでは、さらにいくつかのサンプルコードを提供しています:http://shadynasty.biz/blog/2012/08/07/painless-web-handlers-in-go/最初の投稿をGAE固有の例で編集します。ありがとう:) –

+1

素晴らしい!最初はあなたの心を包み込む(funcは機能を持っていますか?)しかし、それは非常に強力です!私はブログの投稿は私が最初にそれを学んだ場所だと思う。良いシリーズ。 – minikomi

+1

2つのServeHTTPを効果的に直列に持つことができます。最初のマルチプレクサのもの、自分自身のものです。サンプルApp Engineアプリで質問が更新されました。 –

関連する問題