ハンドラーからいくつかの反復ロジックを引き出し、それをハンドラーごとのミドルウェアに入れたいと考えています。具体的には、CSRF チェック、既存のセッション値 (つまり、認証またはプレビュー ページ) のチェックなどです。
これに関するいくつかの記事を読みましたが、多くの例はサーバーごとのミドルウェア (ラッピング) に焦点を当てていますhttp.Handler
: ミドルウェアを必要とする少数のハンドラーのセットがあります。私の他のページのほとんどはそうではありません。したがって、セッションなどのチェックを避けることができれば. それらの要求に適しています。
これまでのところ、私のミドルウェアは通常、次のようになっています。
func checkCSRF(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// get the session, check/validate/create the token based on HTTP method, etc.
// return HTTP 403 on a failed check
// else invoke the wrapped handler h(w, r)
}
}
ただし、多くの場合、ラップされたハンドラーに変数を渡したい: テンプレートに渡すために生成された CSRF トークン、またはフォーム データを含む構造体 — ミドルウェアの 1 つは、保存されたフォーム データの存在を事前にセッションにチェックします。ユーザーが URL にヒットする/preview/
と、それ以外の場合はリダイレクトされます (プレビューするものが何もないためです!)。
その構造体をラップされたハンドラーに渡して、session.Get/type アサーション/エラー チェック ロジックをミドルウェアに記述しなくても済むようにしたいと思います。
私は次のように書くことができます:
type CSRFHandlerFunc func(w http.ResponseWriter, r *http.Request, t string)
...そして、ミドルウェアを次のように記述します。
func csrfCheck(h CSRFHandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// get the session, check/validate/create the/a token based on HTTP method, etc.
// return HTTP 403 on a failed check
// else invoke the wrapped handler and pass the token h(w, r, token)
}
...しかし、それにはいくつかの疑問が生じます:
- これは、ハンドラーごとのミドルウェアを実装し、リクエストごとの変数を渡す賢明な方法ですか?
- これをテストする前に (私の開発マシンにアクセスできません!)、ハンドラーを複数のミドルウェアでラップする必要がある場合は、単に
r.HandleFunc("/path/preview/", checkCSRF(checkExisting(previewHandler)))
? ここで見られる問題は、ミドルウェアが密結合になっていることです。ラップされたミドルウェアは、外側のミドルウェアから変数を受け取って渡す必要があります。これにより、http.HandlerFunc の拡張がトリッキー/複雑になります。 - ゴリラ/コンテキストは、ここにうまく適合し、2 ~ 3 個のカスタム ハンドラー タイプ (またはジェネリック ハンドラー タイプ) の記述を避けることができますか? もしそうなら、それをどのように利用しますか? または、独自の「コンテキスト」マップを実装できますか (同時アクセスで問題が発生しますか?)。
可能な限り、「ライブラリの作成に巻き込まれないように」という罠にはまらないようにしていますが、ミドルウェアは、プロジェクトの後半で追加/構築する可能性が高いものであり、「それを正しくする」ということです。
これに関するいくつかのガイダンスをいただければ幸いです。これまでのところ、 Go は Web アプリケーションを作成するのに優れていますが、この段階ではまだ多くの例がないため、SO に少し頼っています。