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

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

このコミットは、Go言語の net/http パッケージにおける Request 型の ParseForm メソッドと FormValue メソッドのドキュメントを明確化し、ParseForm の戻り値の型宣言における「スタッター(stutter)」を修正するものです。具体的には、ParseFormr.Form を更新すること、およびPOST/PUTリクエストのボディパラメータがURLクエリ文字列の値よりも優先されることを明記し、FormValue のドキュメントに ParseForm の利用を促す記述を追加しています。

コミット

  • コミットハッシュ: 62f54e129478f13954f92a13c4d012f23b05199f
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: Mon Nov 26 20:03:24 2012 +0800

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

https://github.com/golang/go/commit/62f54e129478f13954f92a13c4d012f23b05199f

元コミット内容

net/http: clarify docs of ParseForm and mention ParseForm in docs for FormValue
while we're at it, also fix a return value stutter in ParseForm.

R=bradfitz
CC=golang-dev
https://golang.org/cl/6847074

変更の背景

このコミットの主な目的は、Go言語の標準ライブラリである net/http パッケージのドキュメントの明確性を向上させることです。特に、HTTPリクエストのフォームデータを解析する ParseForm メソッドと、その解析結果から特定の値を取得する FormValue メソッドに関する説明が不十分であったため、開発者がこれらのメソッドを正しく理解し、意図通りに使用できるようにするための改善が行われました。

具体的には、以下の点が背景にあります。

  1. ParseForm の動作の不明瞭さ: 以前のドキュメントでは、ParseFormRequest オブジェクトの Form フィールドを更新するという重要な副作用が明示されていませんでした。また、POST/PUTリクエストのボディパラメータがURLクエリパラメータよりも優先されるという挙動も明確ではありませんでした。これにより、開発者がフォームデータの取得順序や、ParseForm を呼び出すことによる Request オブジェクトの状態変化を誤解する可能性がありました。
  2. FormValue と複数値の取得: FormValue は指定されたキーの最初の値のみを返します。しかし、HTMLフォームでは同じキーで複数の値を送信することが可能です(例: 複数のチェックボックス)。このような場合にすべての値を取得するためには ParseForm を呼び出した後に Request.Form を直接参照する必要があるのですが、その点が FormValue のドキュメントから読み取れませんでした。
  3. Go言語のコーディング規約への準拠: Go言語では、関数の戻り値の型が一つしかない場合、その型名を繰り返して書くことを「スタッター(stutter)」と呼び、避けるべき慣習とされています。ParseForm メソッドのシグネチャが func (r *Request) ParseForm() (err error) となっていたため、これを func (r *Request) ParseForm() error に修正することで、よりGoらしいコードスタイルに準拠させることが意図されました。これは機能的な変更ではなく、コードの可読性と慣習への適合性を高めるための改善です。

これらの改善により、net/http パッケージの使いやすさと堅牢性が向上し、開発者がより正確でバグの少ないWebアプリケーションを構築できるようになります。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびHTTPプロトコルに関する基本的な知識が必要です。

  1. Go言語の net/http パッケージ:

    • Go言語でWebサーバーやHTTPクライアントを構築するための標準ライブラリです。HTTPリクエストの処理、レスポンスの生成、ルーティングなど、Webアプリケーション開発に必要な機能を提供します。
    • http.Request 構造体: HTTPリクエストを表す構造体です。クライアントからのリクエストに関するあらゆる情報(メソッド、URL、ヘッダー、ボディなど)を含みます。
    • Request.Form: url.Values 型のフィールドで、URLのクエリパラメータとPOST/PUTリクエストのボディパラメータ(フォームデータ)を結合したものを保持します。ParseForm または ParseMultipartForm が呼び出された後にデータが格納されます。
    • Request.PostForm: url.Values 型のフィールドで、POSTまたはPUTリクエストのボディから解析されたフォームデータのみを保持します。
    • url.Values: map[string][]string のエイリアスで、キーと値のペア(キーに対して複数の値を持つことができる)を表現するために使用されます。HTTPのクエリパラメータやフォームデータを扱うのに適しています。
  2. HTTPメソッド:

    • GET: サーバーからリソースを取得するために使用されます。データはURLのクエリパラメータとして送信されます。
    • POST: サーバーにデータを送信し、新しいリソースを作成するために使用されます。データはリクエストボディとして送信されます。
    • PUT: サーバー上の既存のリソースを更新するために使用されます。データはリクエストボディとして送信されます。
  3. URLクエリパラメータとリクエストボディ:

    • URLクエリパラメータ: URLの ? の後に続く key=value 形式のデータです(例: http://example.com/search?q=golang&page=1)。主にGETリクエストで使用されます。
    • リクエストボディ: HTTPリクエストの本体部分で、POSTやPUTリクエストで大量のデータを送信する際に使用されます。フォームデータ、JSON、XMLなど、様々な形式のデータを格納できます。
  4. フォームデータの解析:

    • Webアプリケーションでは、HTMLフォームから送信されたデータをサーバー側で解析する必要があります。Goの net/http パッケージは、この解析を自動的に行う機能を提供します。
    • Request.ParseForm(): URLのクエリパラメータと、POST/PUTリクエストのボディ(application/x-www-form-urlencoded または multipart/form-data 形式)を解析し、その結果を Request.Form および Request.PostForm に格納します。このメソッドは冪等(idempotent)であり、複数回呼び出しても同じ結果が得られます。
    • Request.FormValue(key string): ParseForm または ParseMultipartForm を必要に応じて自動的に呼び出し、指定されたキーのフォーム値を取得します。POST/PUTボディパラメータがURLクエリ文字列の値よりも優先されます。
  5. Go言語の「戻り値のスタッター(Return Value Stutter)」:

    • Go言語の慣習として、関数の戻り値が一つしかない場合、その戻り値の型を括弧で囲んで明示的に名前付き戻り値として宣言する形式(例: func foo() (result Type))は、型名が繰り返されるように見えるため「スタッター」と呼ばれ、避けるべきとされています。代わりに、func foo() Type のように直接型を記述する形式が推奨されます。このコミットでは、ParseForm の戻り値の型が (err error) から error に変更され、この慣習に準拠しています。

技術的詳細

このコミットで行われた技術的な変更は、主に src/pkg/net/http/request.go ファイル内の ParseForm および FormValue メソッドのドキュメント文字列(コメント)の更新と、ParseForm メソッドのシグネチャの修正です。

  1. ParseForm メソッドのドキュメントの明確化:

    • 変更前:
      // ParseForm parses the raw query from the URL.
      //
      // For POST or PUT requests, it also parses the request body as a form.
      // POST and PUT body parameters take precedence over URL query string values.
      // If the request Body's size has not already been limited by MaxBytesReader,
      // the size is capped at 10MB.
      //
      // ParseMultipartForm calls ParseForm automatically.
      // It is idempotent.
      
    • 変更後:
      // ParseForm parses the raw query from the URL and updates r.Form.
      //
      // For POST or PUT requests, it also parses the request body as a form and
      // put the results into both r.PostForm and r.Form.
      // POST and PUT body parameters take precedence over URL query string values
      // in r.Form.
      // If the request Body's size has not already been limited by MaxBytesReader,
      // the size is capped at 10MB.
      //
      // ParseMultipartForm calls ParseForm automatically.
      // It is idempotent.
      
    • 詳細:
      • 最初の行に "and updates r.Form" が追加され、ParseFormRequest オブジェクトの Form フィールドを更新するという重要な副作用が明示されました。これは、開発者が ParseForm を呼び出した後に r.Form を参照することで解析されたデータにアクセスできることを明確にします。
      • POST/PUTリクエストに関する説明で、解析結果が "both r.PostForm and r.Form" に格納されることが追記されました。これにより、PostForm がボディパラメータのみを、Form がクエリパラメータとボディパラメータを結合したものを保持するという違いがより明確になります。
      • パラメータの優先順位に関する記述に "in r.Form" が追加され、この優先順位が r.Form に反映されることが強調されました。
  2. ParseForm メソッドのシグネチャの修正(戻り値のスタッターの修正):

    • 変更前:
      func (r *Request) ParseForm() (err error) {
      
    • 変更後:
      func (r *Request) ParseForm() error {
      	var err error
      
    • 詳細:
      • 戻り値の型宣言が (err error) から error に変更されました。これは、Go言語のコーディング規約において、単一の戻り値を持つ関数で戻り値に名前を付ける(名前付き戻り値)ことで型名が繰り返される「スタッター」を避けるための修正です。機能的な変更はなく、コードのスタイルと可読性を向上させるためのものです。
      • 名前付き戻り値 err が削除されたため、関数内で var err error と明示的に err 変数を宣言する行が追加されました。
  3. FormValue メソッドのドキュメントの明確化:

    • 変更前:
      // FormValue returns the first value for the named component of the query.
      // POST and PUT body parameters take precedence over URL query string values.
      // FormValue calls ParseMultipartForm and ParseForm if necessary.
      
    • 変更後:
      // FormValue returns the first value for the named component of the query.
      // POST and PUT body parameters take precedence over URL query string values.
      // FormValue calls ParseMultipartForm and ParseForm if necessary.
      // To access multiple values of the same key use ParseForm.
      
    • 詳細:
      • 最後の行に "To access multiple values of the same key use ParseForm." が追加されました。これは、FormValue が単一の値しか返さないため、同じキーを持つ複数の値(例: 複数のチェックボックス)を取得したい場合には、ParseForm を呼び出した後に Request.Form を直接参照する必要があることを開発者に明確に伝えるための重要な情報です。

これらの変更は、Goの net/http パッケージのドキュメントの精度と完全性を高め、開発者がWebアプリケーションでフォームデータを扱う際の混乱を減らすことを目的としています。

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

--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -643,16 +643,20 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
 	return
 }
 
-// ParseForm parses the raw query from the URL.
+// ParseForm parses the raw query from the URL and updates r.Form.
+//
+// For POST or PUT requests, it also parses the request body as a form and
+// put the results into both r.PostForm and r.Form.
+// POST and PUT body parameters take precedence over URL query string values
+// in r.Form.
 //
-// For POST or PUT requests, it also parses the request body as a form.
-// POST and PUT body parameters take precedence over URL query string values.
 // If the request Body's size has not already been limited by MaxBytesReader,
 // the size is capped at 10MB.
 //
 // ParseMultipartForm calls ParseForm automatically.
 // It is idempotent.
-func (r *Request) ParseForm() (err error) {
+func (r *Request) ParseForm() error {
+\tvar err error
 \tif r.PostForm == nil {\
 \t\tif r.Method == \"POST\" || r.Method == \"PUT\" {\
 \t\t\tr.PostForm, err = parsePostForm(r)\
@@ -728,6 +732,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
 // FormValue returns the first value for the named component of the query.\
 // POST and PUT body parameters take precedence over URL query string values.\
 // FormValue calls ParseMultipartForm and ParseForm if necessary.\
+// To access multiple values of the same key use ParseForm.\
 func (r *Request) FormValue(key string) string {\
  \tif r.Form == nil {\
  \t\tr.ParseMultipartForm(defaultMaxMemory)\

コアとなるコードの解説

上記のdiffは、src/pkg/net/http/request.go ファイルにおける以下の3つの主要な変更を示しています。

  1. ParseForm メソッドのドキュメントコメントの変更:

    • - // ParseForm parses the raw query from the URL.
      • 元のドキュメントの最初の行です。
    • + // ParseForm parses the raw query from the URL and updates r.Form.
      • ParseFormRequest オブジェクトの Form フィールドを更新するという重要な情報を追加しました。これにより、開発者はこのメソッドが単に解析するだけでなく、リクエストオブジェクトの状態を変更することを明確に理解できます。
    • - // For POST or PUT requests, it also parses the request body as a form.
      • 元のドキュメントのPOST/PUTリクエストに関する説明です。
    • + // For POST or PUT requests, it also parses the request body as a form and
    • + // put the results into both r.PostForm and r.Form.
      • POST/PUTリクエストのボディが解析された結果が、r.PostFormr.Form の両方に格納されることを明示しました。これは、r.PostForm がボディデータのみを、r.Form がURLクエリとボディデータを結合したものを保持するという Request 構造体の設計をより正確に反映しています。
    • - // POST and PUT body parameters take precedence over URL query string values.
      • 元のドキュメントの優先順位に関する説明です。
    • + // POST and PUT body parameters take precedence over URL query string values
    • + // in r.Form.
      • POST/PUTボディパラメータがURLクエリ文字列の値よりも優先されるというルールが、具体的に r.Form に適用されることを明確にしました。
  2. ParseForm メソッドのシグネチャの変更(戻り値のスタッターの修正):

    • - func (r *Request) ParseForm() (err error) {
      • 元の ParseForm メソッドのシグネチャです。err error という名前付き戻り値が使用されています。
    • + func (r *Request) ParseForm() error {
      • 戻り値の型宣言から err という名前が削除され、単に error となりました。これはGo言語のコーディング規約で推奨されるスタイルであり、単一の戻り値を持つ関数で戻り値に名前を付けることによる「スタッター」を避けるための修正です。
    • + \tvar err error
      • 名前付き戻り値が削除されたため、関数内で err 変数を使用する前に明示的に var err error と宣言する必要が生じました。これは機能的な変更ではなく、シグネチャの変更に伴うコードの調整です。
  3. FormValue メソッドのドキュメントコメントの変更:

    • + // To access multiple values of the same key use ParseForm.
      • FormValue が単一の値しか返さないため、同じキーを持つ複数の値を取得したい場合には ParseForm を呼び出した後に Request.Form を直接参照する必要があることを開発者に促す新しい行が追加されました。これは、FormValue の限界と、より高度なフォームデータ処理のための適切なアプローチを明確にするものです。

これらの変更は、Goの net/http パッケージのドキュメントの正確性、完全性、およびGoのコーディング慣習への準拠を向上させることを目的としています。

関連リンク

参考にした情報源リンク