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

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

このコミットは、Go言語のドキュメントツールであるgodocコマンドラインツールにおいて、ローカルでgodocを実行しているユーザーに対して、Go Playgroundの機能(コードのコンパイルや共有)が利用できないことをより明確に通知するための変更です。具体的には、Go Playgroundのバックエンド機能がローカルのgodocサーバーには実装されていないため、ユーザーがこれらの機能を使おうとした際に、一般的なエラーメッセージではなく、より具体的な「この機能はローカルのgodocでは利用できません」というメッセージが表示されるように改善されています。

コミット

commit abdb4dbe2c9c3315f23f68b784fd995e3c5705f7
Author: Andrew Gerrand <adg@golang.org>
Date:   Tue Mar 20 14:11:38 2012 +1100

    cmd/godoc: inform users that the playground doesn't work via local godoc
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5843065

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

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

元コミット内容

cmd/godoc: inform users that the playground doesn't work via local godoc

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

変更の背景

Go言語の公式ウェブサイト(golang.org)には、Go Playgroundと呼ばれるインタラクティブなコード実行環境が組み込まれています。これは、ユーザーがGoのコードをブラウザ上で記述し、コンパイルして実行結果を確認したり、他のユーザーとコードを共有したりできる非常に便利な機能です。

godocコマンドは、Goのソースコードからドキュメントを生成し、ローカルでHTTPサーバーとして提供するツールです。これにより、開発者はオフライン環境やプライベートなネットワーク内でGoのドキュメントを閲覧できます。しかし、ローカルで実行されるgodocサーバーは、Go Playgroundのコードコンパイルや共有といったバックエンド処理を行う機能を持っていません。これらの機能は、golang.orgのサーバーサイドで提供される特別なサービスに依存しています。

このため、ユーザーがローカルのgodocサーバーを通じてGo Playgroundの機能を使おうとすると、バックエンドサービスへの接続エラーが発生していました。以前の実装では、このエラーはJavaScript側で捕捉され、「Error communicating with remote server.」(リモートサーバーとの通信エラー)という一般的なメッセージが表示されるだけでした。このメッセージは、なぜ機能が利用できないのか、その根本的な理由をユーザーに伝えていませんでした。

このコミットの背景には、ユーザーエクスペリエンスの向上という明確な目的があります。ローカルgodocの制限をユーザーに明確に伝えることで、混乱を避け、不必要なトラブルシューティングの時間を削減することが意図されています。

前提知識の解説

Go Playground

Go Playgroundは、Go言語のコードをブラウザ上で実行できるウェブサービスです。特徴としては、以下が挙げられます。

  • インタラクティブな実行: ユーザーが入力したGoコードをサーバーサイドでコンパイル・実行し、その結果をブラウザに返します。
  • 共有機能: コードを永続的なURLとして保存し、他のユーザーと簡単に共有できます。
  • サンドボックス環境: セキュリティのために、実行環境は厳しく制限されたサンドボックス内で動作します。ファイルシステムへのアクセスやネットワーク通信は制限されます。
  • 特定のGoバージョン: 通常、特定の安定版Goコンパイラが使用されます。

Go Playgroundのバックエンドは、Go言語で書かれた特別なサービスであり、コードのコンパイル、実行、結果のキャッシング、共有URLの生成などを担当しています。

godocコマンド

godocはGo言語の標準ツールの一つで、Goのソースコードからドキュメントを生成し、ウェブブラウザで閲覧可能な形式で提供します。

  • ドキュメント生成: Goのパッケージ、関数、型、変数などのコメントから自動的にドキュメントを生成します。
  • ローカルサーバー: godoc -http=:6060のように実行することで、指定されたポートでHTTPサーバーを起動し、ローカルマシンからドキュメントを閲覧できるようにします。
  • Go Playgroundとの連携: 公式のgodocウェブサイト(golang.org/pkg/など)では、ドキュメント内のコード例にGo Playgroundの機能が組み込まれており、その場でコードを実行・編集できます。

HTTPステータスコード 501 Not Implemented

HTTPステータスコード501 (Not Implemented) は、サーバーがリクエストメソッドを認識しないか、またはそのリクエストを処理する能力がないことを示します。この場合、サーバーはリクエストされた機能を提供できないことをクライアントに明確に伝えます。このコミットでは、ローカルgodocサーバーがGo Playgroundのコンパイル・共有機能を提供できないため、このステータスコードが適切に使用されています。

AJAX (Asynchronous JavaScript and XML)

AJAXは、ウェブページ全体をリロードすることなく、サーバーと非同期でデータをやり取りする技術です。Go Playgroundのフロントエンド(JavaScript)は、ユーザーが「Run」ボタンをクリックした際に、AJAXリクエストを使用してGoコードをバックエンドサーバーに送信し、実行結果を受け取ります。エラーが発生した場合、このAJAXリクエストのコールバック関数がエラーを処理します。

技術的詳細

このコミットは、フロントエンド(JavaScript)とバックエンド(Go)の両方に変更を加えて、Go Playgroundの機能がローカルgodocで利用できない場合のユーザー通知を改善しています。

バックエンド (src/cmd/godoc/main.go) の変更

  1. 新しいハンドラの登録: http.HandleFunc("/compile", disabledHandler) http.HandleFunc("/share", disabledHandler) これらの行が追加され、/compile/shareというパスへのHTTPリクエストがdisabledHandlerという新しい関数によって処理されるようになりました。これらはGo Playgroundのコンパイルと共有機能に対応するエンドポイントです。

  2. disabledHandler関数の追加:

    // disabledHandler serves a 501 "Not Implemented" response.
    func disabledHandler(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNotImplemented)
        fmt.Fprint(w, "This functionality is not available via local godoc.")
    }
    

    この関数は、HTTPレスポンスのステータスコードをhttp.StatusNotImplemented(501)に設定し、レスポンスボディとして「This functionality is not available via local godoc.」というメッセージを書き込みます。これにより、ローカルgodocサーバーは、これらの機能がサポートされていないことを明示的にクライアントに通知します。

フロントエンド (doc/play/playground.js) の変更

JavaScript側では、AJAXリクエストのエラーハンドリングが強化されています。

  1. errorコールバックの改善: 以前は、AJAXリクエストがエラーを返した場合、常にoutput.addClass("error").text("Error communicating with remote server.");という汎用的なメッセージが表示されていました。 変更後、errorコールバック関数はxhrオブジェクト(XMLHttpRequestオブジェクト)を受け取るようになり、そのstatusプロパティをチェックします。

    error: function(xhr) {
        var text = "Error communicating with remote server.";
        console.log(xhr.status); // デバッグ用にステータスをログ出力
        if (xhr.status == 501) {
            text = xhr.responseText; // 501の場合、サーバーからの具体的なメッセージを使用
        }
        output.addClass("error").text(text);
    }
    

    もしxhr.statusが501であれば、サーバーから送られてきたxhr.responseText(この場合は「This functionality is not available via local godoc.」)をエラーメッセージとして表示するように変更されました。これにより、ユーザーはより具体的なエラー情報を得ることができます。

  2. completeコールバックの改善 (共有機能): 共有機能(/shareエンドポイントへのリクエスト)のcompleteコールバックにも同様のロジックが追加されました。

    complete: function(xhr) {
        sharing = false;
        if (xhr.status == 501) {
            alert(xhr.responseText); // 501の場合、アラートでサーバーからのメッセージを表示
            return;
        }
        if (xhr.status != 200) {
            alert("Server error; try again.");
            return;
        }
        // ... (成功時の処理)
    }
    

    ここでも、xhr.statusが501であれば、サーバーからのメッセージをalertダイアログで表示し、それ以上の処理を行わないようにしています。これにより、共有機能が利用できない場合もユーザーに明確に通知されます。

これらの変更により、ローカルgodocでGo Playgroundの機能を使おうとした際に、サーバーが501エラーを返し、その具体的なメッセージがフロントエンドで表示されるという、よりユーザーフレンドリーな挙動が実現されました。

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

doc/play/playground.js

--- a/doc/play/playground.js
+++ b/doc/play/playground.js
@@ -166,10 +166,13 @@ function playground(opts) {
 				}
 				pre.text(out);
 			},
-			error: function() {
-				output.addClass("error").text(
-					"Error communicating with remote server."
-				);
+			error: function(xhr) {
+				var text = "Error communicating with remote server.";
+				console.log(xhr.status);
+				if (xhr.status == 501) {
+					text = xhr.responseText;
+				}
+				output.addClass("error").text(text);
 			}
 		});
 	}
@@ -190,6 +193,10 @@ function playground(opts) {
 			type: "POST",
 			complete: function(xhr) {
 				sharing = false;
+				if (xhr.status == 501) {
+					alert(xhr.responseText);
+					return;
+				}
 				if (xhr.status != 200) {
 					alert("Server error; try again.");
 					return;

src/cmd/godoc/main.go

--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -274,6 +274,10 @@ func main() {
 
 		registerPublicHandlers(http.DefaultServeMux)
 
+		// Playground handlers are not available in local godoc.
+		http.HandleFunc("/compile", disabledHandler)
+		http.HandleFunc("/share", disabledHandler)
+
 		// Initialize default directory tree with corresponding timestamp.
 		// (Do it in a goroutine so that launch is quick.)
 		go initFSTree()
@@ -450,3 +454,9 @@ type httpWriter struct {
 
 func (w *httpWriter) Header() http.Header  { return w.h }
 func (w *httpWriter) WriteHeader(code int) { w.code = code }
+
+// disabledHandler serves a 501 "Not Implemented" response.
+func disabledHandler(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusNotImplemented)
+	fmt.Fprint(w, "This functionality is not available via local godoc.")
+}

コアとなるコードの解説

src/cmd/godoc/main.go の変更点

  • http.HandleFunc("/compile", disabledHandler)http.HandleFunc("/share", disabledHandler): Goの標準ライブラリnet/httpパッケージの機能を使用して、特定のURLパス(/compile/share)に対するHTTPリクエストを、disabledHandlerという関数で処理するように登録しています。これにより、これらのパスへのリクエストが来た際に、disabledHandlerが呼び出されます。コメント// Playground handlers are not available in local godoc.が、この変更の意図を明確に示しています。

  • disabledHandler 関数: この新しい関数は、http.ResponseWriter*http.Requestを引数にとる、典型的なHTTPハンドラ関数のシグネチャを持っています。

    • w.WriteHeader(http.StatusNotImplemented): HTTPレスポンスのステータスコードを501 (Not Implemented) に設定します。これは、サーバーがリクエストされた機能を提供できないことをクライアントに伝える標準的な方法です。
    • fmt.Fprint(w, "This functionality is not available via local godoc."): レスポンスボディに、ユーザー向けの具体的なエラーメッセージを書き込みます。このメッセージは、フロントエンドのJavaScriptによって読み取られ、ユーザーに表示されます。

doc/play/playground.js の変更点

  • error コールバックの変更: Go Playgroundのコード実行(/compileへのAJAXリクエスト)がエラーを返した場合に呼び出されるerrorコールバック関数が修正されました。

    • function(xhr): コールバック関数がxhrオブジェクト(XMLHttpRequestオブジェクト)を受け取るようになりました。このオブジェクトには、HTTPレスポンスのステータスコードやレスポンステキストなどの情報が含まれています。
    • if (xhr.status == 501): サーバーから返されたHTTPステータスコードが501であるかをチェックします。
    • text = xhr.responseText;: もしステータスコードが501であれば、サーバーから送られてきたレスポンスボディ(disabledHandlerが書き込んだメッセージ)をエラーテキストとして使用します。これにより、汎用的なエラーメッセージではなく、サーバーからの具体的なメッセージが表示されるようになります。
    • output.addClass("error").text(text);: 最終的に、決定されたエラーテキストをHTML要素に表示し、エラーを示すCSSクラスを追加します。
  • complete コールバックの変更 (共有機能): Go Playgroundのコード共有(/shareへのAJAXリクエスト)が完了した際に呼び出されるcompleteコールバック関数にも同様のロジックが追加されました。

    • if (xhr.status == 501): ここでもステータスコードが501であるかをチェックします。
    • alert(xhr.responseText);: 501の場合、サーバーからのメッセージをJavaScriptのalertダイアログで表示します。これは、ユーザーに即座に通知するための一般的なUIパターンです。
    • return;: alert表示後、それ以上の処理を行わずにコールバックを終了します。これにより、共有機能が利用できない場合に不適切な後続処理が実行されるのを防ぎます。

これらの変更は、クライアントとサーバー間の協調によって、より情報豊富でユーザーフレンドリーなエラーハンドリングを実現しています。サーバーは機能が利用できないことを明示的に通知し、クライアントはその通知を解釈してユーザーに分かりやすく表示します。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • MDN Web Docs (Mozilla Developer Network)
  • GitHubのコミット履歴と差分表示