Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12916] ファイルの概要

このコミットは、Go言語の標準ライブラリである net/http パッケージの example_test.go ファイルに、http.FileServerhttp.StripPrefix の使用例を追加するものです。具体的には、src/pkg/net/http/example_test.go ファイルに5行の追加が行われました。

コミット

commit acb550504fa77e16070405fd5a89770a416de75b
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Fri Apr 20 00:41:10 2012 +0800

    net/http: add example for FileServer to mention StripPrefix
            Fixes #3530.
    
    R=golang-dev, rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/6032052

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/acb550504fa77e16070405fd5a89770a416de75b

元コミット内容

net/http: add example for FileServer to mention StripPrefix
        Fixes #3530.

変更の背景

このコミットの背景には、net/http パッケージの FileServer を使用して静的ファイルを配信する際に、特定のURLパスからファイルを配信するための一般的なパターンである http.StripPrefix との組み合わせ方について、ユーザーが混乱していたという問題があったと考えられます。コミットメッセージにある "Fixes #3530" は、この変更がGoのIssueトラッカーで報告された問題3530を解決するものであることを示しています。

http.FileServer は指定されたディレクトリのファイルをそのまま提供しますが、ウェブアプリケーションではしばしば、特定のURLプレフィックス(例: /static/)の下にファイルを配置し、そのプレフィックスを内部的なファイルパスから取り除いてから FileServer に渡す必要があります。この「プレフィックスの除去」の概念が、特に初心者にとっては直感的ではない場合があり、公式の例が不足していたことで、誤った実装や理解不足が生じていた可能性があります。

このコミットは、そのような一般的なユースケースに対する明確な例を提供することで、開発者が net/http パッケージをより効果的に利用できるようにすることを目的としています。

前提知識の解説

このコミットを理解するためには、Go言語の net/http パッケージにおける以下の基本的な概念を理解しておく必要があります。

  • net/http パッケージ: Go言語の標準ライブラリで、HTTPクライアントとサーバーの実装を提供します。ウェブアプリケーションを構築する上で中心的な役割を担います。
  • http.Handler インターフェース: HTTPリクエストを処理するためのインターフェースです。ServeHTTP(ResponseWriter, *Request) メソッドを実装することで、任意の型がHTTPハンドラとして機能できます。
  • http.Handle 関数: 特定のURLパス(パターン)と http.Handler を関連付け、HTTPリクエストがそのパスにマッチした際に指定されたハンドラが呼び出されるように登録します。
  • http.FileServer(root http.FileSystem) http.Handler: 指定された http.FileSystem からファイルをHTTPリクエストに応じて提供する http.Handler を返します。これは静的ファイル(HTML、CSS、JavaScript、画像など)を配信する際に非常に便利です。
  • http.Dir(dir string) FileSystem: オペレーティングシステムのファイルシステム上の指定されたディレクトリを http.FileSystem インターフェースとしてラップします。これにより、http.FileServer が実際のディスク上のファイルにアクセスできるようになります。
  • http.StripPrefix(prefix string, h http.Handler) http.Handler: この関数は、http.Handler をラップし、そのハンドラにリクエストを渡す前に、リクエストURLのパスから指定された prefix を取り除きます。これは、URLパスとファイルシステム上のパスの間にずれがある場合に特に重要です。例えば、/tmpfiles/somefile というURLで /tmp/somefile を提供したい場合、/tmpfiles/ というプレフィックスを取り除く必要があります。StripPrefix は、指定されたプレフィックスで始まらないパスへのリクエストに対しては、HTTP 404 (Not Found) エラーを返します。

技術的詳細

http.FileServer は、その root 引数で指定された http.FileSystem のルートディレクトリを基準として、リクエストされたURLパスに対応するファイルを検索します。例えば、http.FileServer(http.Dir("/tmp")) の場合、/somefile.txt というリクエストが来ると、/tmp/somefile.txt を探します。

しかし、ウェブアプリケーションでは、しばしば特定のURLパスの下に静的ファイルをまとめて配置したい場合があります。例えば、/tmpfiles/ というURLパスで /tmp ディレクトリの内容を公開したいとします。もし単純に http.Handle("/tmpfiles/", http.FileServer(http.Dir("/tmp"))) とすると、/tmpfiles/somefile というリクエストが来た際に、FileServer/tmp/tmpfiles/somefile を探してしまい、意図した動作になりません。

ここで http.StripPrefix が必要になります。http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))) のように組み合わせることで、以下のようになります。

  1. クライアントから /tmpfiles/somefile というリクエストが来る。
  2. http.Handle("/tmpfiles/", ...) によって、このリクエストが登録されたハンドラにルーティングされる。
  3. ハンドラは http.StripPrefix によってラップされているため、まずリクエストURLパスから /tmpfiles/ が取り除かれる。結果として、内部的なパスは /somefile となる。
  4. http.StripPrefix は、この修正されたパス (/somefile) を持つリクエストを、ラップしている http.FileServer(http.Dir("/tmp")) に渡す。
  5. http.FileServer は、そのルートディレクトリ /tmp を基準に /somefile を探し、結果として /tmp/somefile を提供する。

この一連の流れが、URLパスと実際のファイルパスのマッピングを正しく行うために不可欠です。このコミットで追加された例は、この一般的なパターンを明確に示し、開発者が FileServer を適切に利用できるようにするためのものです。

コアとなるコードの変更箇所

--- a/src/pkg/net/http/example_test.go
+++ b/src/pkg/net/http/example_test.go
@@ -49,3 +49,8 @@ func ExampleGet() {
 	res.Body.Close()
 	fmt.Printf("%s", robots)
 }
+
+func ExampleFileServer() {
+	// we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile
+	http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
+}

コアとなるコードの解説

追加されたコードは ExampleFileServer という関数で、GoのテストパッケージにおけるExample関数として機能します。Example関数は、パッケージのドキュメントにコード例として表示され、go test コマンドで実行可能であり、その出力が期待される出力と一致するかどうかも検証されます。これにより、ドキュメントの正確性とコードの動作が保証されます。

func ExampleFileServer() {
	// we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile
	http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
}
  • func ExampleFileServer() { ... }: これはGoのExample関数です。この関数内のコードは、net/http パッケージのドキュメントに FileServer の使用例として表示されます。
  • // we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile: このコメントは、なぜ StripPrefix を使用するのかを簡潔に説明しています。/tmpfiles/somefile というURLパスが、実際のファイルシステム上の /tmp/somefile にマッピングされるようにするためです。
  • http.Handle("/tmpfiles/", ...): これは、/tmpfiles/ で始まるすべてのHTTPリクエストを処理するためのハンドラを登録しています。末尾のスラッシュ (/) は、このパスとそのサブパスの両方をカバーすることを示します。
  • http.StripPrefix("/tmpfiles/", ...): ここがこの例の核心です。
    • 最初の引数 "/tmpfiles/" は、リクエストURLパスから取り除くプレフィックスを指定します。
    • 二番目の引数 http.FileServer(http.Dir("/tmp")) は、プレフィックスが取り除かれた後のリクエストを処理する実際のハンドラです。
  • http.FileServer(http.Dir("/tmp")): これは、/tmp ディレクトリの内容を静的ファイルとして提供する http.Handler を作成します。http.Dir("/tmp") は、オペレーティングシステムの /tmp ディレクトリを http.FileSystem インターフェースとしてラップします。

この一行のコードは、net/http を使って特定のURLパスから静的ファイルを効率的かつ安全に提供するための、非常に一般的で重要なパターンを簡潔に示しています。

関連リンク

参考にした情報源リンク