入門メモ㉚で使用した標準パッケージの使い方のおさらい。
急にたくさんの関数やメソッドがでてきてパニックになってしまったのでおさらいをする。
また、htmlファイルも簡単にタグの意味を備忘としてメモしておく。
入門メモ㉚webアプリ作成について
コードとしてはmainファイル、viewページのhtmlファイル、editページのhtmlファイルの3種類。
mainファイルについて
インポートセクション
import (
"html/template"
"log"
"net/http"
"os"
)
■"net/http" パッケージ
役割:HTTPクライアントとサーバーの実装を提供します。Webサーバーを構築し、HTTPリクエストとレスポンスを処理するための機能が含まれています。
Page構造体の定義
type Page struct {
Title string
Body []byte
}
type Page struct { ... }:Pageという新しい構造体(カスタムデータ型)を定義しています。構造体はデータをまとめて扱うためのものです。
■フィールド
Title string:ページのタイトルを表す文字列型のフィールドです。
Body []byte:ページの本文をバイトスライスとして保持するフィールドです。[]byteはバイトの配列(バイトスライス)で、テキストデータを扱うのに適しています。
■意味
この構造体は、シンプルなウェブページやドキュメントを表現するために使われます。タイトルと本文を持つページを表すデータ型です。
saveメソッドの定義
func (p *Page) save() error {
filename := p.Title + ".txt"
return os.WriteFile(filename, p.Body, 0600)
}
func (p *Page) save() error { ... }:Page構造体のインスタンスに対するメソッドsaveを定義しています。このメソッドはエラーを返す可能性があります。
■受け取るもの
(p *Page):Page構造体のポインタpを受け取ります。ポインタを使うことで、元のデータを直接操作できます。
■処理内容
1.ファイル名の生成
p.Titleに.txtを追加して、保存するファイル名を決定します。
例えば、タイトルが"SamplePage"なら、ファイル名は"SamplePage.txt"になります。
2.ファイルへの書き込み
os.WriteFile関数を使って、p.Bodyをファイルに書き込みます。
このメソッドは、Page構造体のデータをテキストファイルとして保存する機能を提供します。
■引数
filename:書き込むファイルの名前。
p.Body:ファイルに書き込む内容(バイトスライス)。
0600:ファイルのパーミッション(アクセス権)を示す数値。0600は、所有者のみが読み書き可能です。
■戻り値
エラーが発生した場合はエラーを返し、成功した場合はnilを返す。
loadPage関数の定義
func loadPage(title string) (*Page, error) {
filename := title + ".txt"
body, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
return &Page{Title: title, Body: body}, nil
}
func loadPage(title string) (*Page, error):タイトルを受け取り、Page構造体のポインタとエラーを返す関数。
この関数は、指定されたタイトルのページをファイルから読み込み、Page構造体として返します。
■引数
title string:読み込みたいページのタイトルを表す文字列。
■処理内容
1.ファイル名の生成
引数で受け取ったtitleに.txtを追加して、読み込むファイル名を決定します。
2.ファイルの読み込み
os.ReadFile関数を使って、指定したファイルからデータを読み込みます。
戻り値
body:ファイルの内容がバイトスライスとして格納されます。
err:エラー情報が格納されます。ファイルが存在しない場合などにエラーが発生します。
3.エラーハンドリング
エラーが発生した場合、nilとエラーを返します。
4.Page構造体の作成
新しいPage構造体を作成し、そのポインタを返します。
・フィールド
Title:引数で受け取ったタイトル。
Body:読み込んだファイルの内容。
・エラー
正常に読み込めた場合なので、エラーはnilです。
ハンドラー関数たち
そもそも、「ハンドラー関数」というのは、以下のような役割を持っている関数を指す。
・リクエストの受け取り:ハンドラー関数は、ユーザーがWebページにアクセスした際に送られてくるHTTPリクエストを受け取ります。
・処理の実行:受け取ったリクエストに基づいて、必要な処理を実行します。例えば、データベースからデータを取得したり、計算を行ったりします。
・レスポンスの返送:処理結果を基に、ユーザーに対してHTTPレスポンス(Webページの内容など)を返します。
各関数でnet/httpパッケージの型や関数が使われている。
viewHandler関数
func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len("/view/"):]
p, err := loadPage(title)
if err != nil {
http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
renderTemplate(w, "view", p)
}
■引数
・w http.ResponseWriter:HTTPレスポンスを返すためのインターフェース。レスポンスのヘッダーやボディを書き込むことができます。
・r *http.Request:HTTPリクエストの情報が入っています。リクエストされたURLやメソッド、ヘッダー、ボディなどを参照できます。
■使われているnet/http関連の項目
・r.URL.Path
URLのパス部分を表す文字列です。例えば、/view/FrontPageのようなパスを取得できます。
・http.Redirect
・役割:クライアント(ブラウザ)にリダイレクトを指示します。
・引数
w:http.ResponseWriter。レスポンスを書き込むためのもの。
r:*http.Request。現在のリクエスト情報。
"/edit/"+title:リダイレクト先のURL。
http.StatusFound:HTTPステータスコード302(Found)を指定しています。
editHandler関数
func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len("/edit/"):]
p, err := loadPage(title)
if err != nil {
p = &Page{Title: title}
}
renderTemplate(w, "edit", p)
}
viewHandlerと同様に、http.ResponseWriterと*http.Requestを引数に取ります。
r.URL.Pathを使ってリクエストされたパスからタイトルを抽出しています。
saveHandler関数
func saveHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[len("/save/"):]
body := r.FormValue("body")
p := &Page{Title: title, Body: []byte(body)}
err := p.save()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
■r.FormValue("body")
・役割:HTTPリクエストのフォームデータから指定したキーの値を取得します。
・用途:
から送信されたデータを受け取るために使用します。■http.Redirect
保存後、ユーザーをビュー画面にリダイレクトします。
renderTemplate関数
func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
t, err := template.ParseFiles(tmpl + ".html")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = t.Execute(w, p)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
■t.Execute(w, p)
template.Template のExecuteメソッド
・役割:テンプレートにデータを差し込み、結果をwに書き込みます。
■エラーハンドリングでのhttp.Error
・役割:指定されたエラーメッセージとステータスコードでHTTPエラーをレスポンスとして返します。
main関数内でのHTTPサーバの設定
func main() {
http.HandleFunc("/view/", viewHandler)
http.HandleFunc("/edit/", editHandler)
http.HandleFunc("/save/", saveHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
■http.HandleFunc
・役割:特定のパターンのURLパスに対してハンドラー関数を登録します。
・使用方法:http.HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
・例
"/view/"へのリクエストはviewHandlerで処理されます。
"/edit/"へのリクエストはeditHandlerで処理されます。
"/save/"へのリクエストはsaveHandlerで処理されます。
■http.ListenAndServe
・役割:指定したアドレス(ここでは:8080)でHTTPサーバーを開始します。
・引数
":8080":サーバーが待ち受けるアドレスとポート。":8080"はポート8080で全てのネットワークインターフェースで待ち受けます。
nil:ハンドラを指定しますが、nilの場合はデフォルトのマルチプレクサ(http.DefaultServeMux)が使用されます。
■log.Fatal
・役割:エラーが発生した場合にログを記録し、プログラムを終了します。
HTTP関連の型や関数の詳細解説
HTTP関連の型や関数の詳細解説
- http.ResponseWriter
概要:サーバーがクライアントにレスポンスを返すためのインターフェース。
主なメソッド
Write([]byte) (int, error):レスポンスボディにデータを書き込みます。
WriteHeader(statusCode int):レスポンスのステータスコードを設定します。
- *http.Request
概要:クライアントからサーバーへのHTTPリクエストの情報を保持する構造体。
主なフィールド
Method:HTTPメソッド(GET, POSTなど)。
URL:リクエストされたURLの情報。
Header:リクエストヘッダーのマップ。
Body:リクエストボディの読み取り用。
- http.HandleFunc
概要:指定したパターンにマッチするURLに対して、ハンドラー関数を登録します。
使い方
http.HandleFunc("/path/", handlerFunction)
注意点:パターンは前方一致でマッチします。
- http.ListenAndServe
概要:HTTPサーバーを開始します。
使い方
http.ListenAndServe(":8080", nil)
引数
addr:待ち受けるアドレスとポート。
handler:nilの場合、http.DefaultServeMuxを使用します。
- http.Redirect
概要:クライアントにリダイレクトを指示するヘッダーを送信します。
使い方
http.Redirect(w, r, "/redirectURL", statusCode)
典型的なステータスコード
http.StatusFound(302):リソースが一時的に移動した。
http.StatusMovedPermanently(301):リソースが恒久的に移動した。
- http.Error
概要:エラーメッセージとステータスコードをクライアントに送信します。
使い方
http.Error(w, "Error message", http.StatusInternalServerError)
- フォームデータの取得
r.FormValue("key")
概要:HTTPリクエストからフォームデータを取得します。
使い方
value := r.FormValue("key")
注意点:この関数はGETおよびPOSTの両方のフォームデータを取得します。
おまけ
ハンドラー関数の引数である w http.ResponseWriter と r *http.Request について理解が浅かったので、AIにわかりやすく解説してもらった。
承知しました!ハンドラー関数の引数である w http.ResponseWriter
と r *http.Request
について、分かりやすい例えを交えながら説明します。
ハンドラー関数とは?
まず、Go言語におけるハンドラー関数は、ウェブサーバーがクライアント(ユーザー)からのリクエストを受け取ったときに呼び出される関数です。その際に、以下の2つの引数を取ります:
w http.ResponseWriter
r *http.Request
これらは、それぞれリクエストとレスポンスを扱うためのものです。
例え:レストランの注文と配膳
レストランを例にして考えてみましょう。
- お客さん:ウェブサイトにアクセスするユーザー(クライアント)
-
注文票:お客さんからのリクエスト(
*http.Request
) - シェフ:サーバー側のハンドラー関数
-
お皿:レスポンスを書き込むためのもの(
http.ResponseWriter
) - 料理:レスポンスとして返すデータ(HTMLなど)
流れ
-
お客さんが注文する:
お客さんがメニューを見て、料理を注文します。これは、ユーザーがウェブサイトにアクセスしてリクエストを送信することに相当します。その際、注文票(
*http.Request
)に注文内容や特別なリクエスト(例えば、辛さ控えめなど)が書かれています。 -
シェフが注文票を受け取る:
シェフ(ハンドラー関数)は、ウェイターから注文票を受け取ります。この注文票には、お客さんのテーブル番号(URL)、注文内容(リクエストのパスやクエリパラメータ)、特別なリクエスト(ヘッダー情報)などが含まれています。
-
シェフが料理を作る:
シェフは注文票を元に料理(レスポンス)を準備します。必要に応じて、材料を調達したり、調理法を調整したりします。
-
料理をお皿に盛り付ける:
出来上がった料理は、お皿(
http.ResponseWriter
)に盛り付けられます。このお皿は、お客さんに料理を提供するための媒体です。 -
料理がお客さんに届けられる:
お皿に乗った料理は、ウェイターを通じてお客さんに届けられます。これが、サーバーからクライアントへのレスポンスに相当します。
r *http.Request
の詳細
役割
- 注文票(リクエスト):お客さんが何を求めているのかを知るための情報源です。
-
含まれる情報:
- メソッド:GETやPOSTなど、どのようなリクエストなのか。
- URL:どのページやリソースを求めているのか。
- ヘッダー:追加の指示や情報(例:ユーザーエージェント、クッキーなど)。
- ボディ:フォームデータやJSONなど、リクエストに含まれる内容。
例
-
注文の詳細を読む:
func handler(w http.ResponseWriter, r *http.Request) { // リクエストされたURLパスを取得 path := r.URL.Path // クエリパラメータを取得 query := r.URL.Query() // リクエストメソッドを取得(GET, POSTなど) method := r.Method }
ポイント
-
r
を使って、クライアントが何を求めているかを知ることができます。 - リクエストの内容に応じて、適切な処理を行います。
w http.ResponseWriter
の詳細
役割
- お皿(レスポンス):シェフが作った料理を盛り付けて、お客さんに提供するためのものです。
-
できること:
- ヘッダーの設定:レスポンスの種類やエンコーディングなどを指定できます。
- ボディへの書き込み:実際にクライアントに返すデータ(HTML、JSONなど)を書き込みます。
- ステータスコードの設定:レスポンスの状態を示すコード(200 OK、404 Not Foundなど)を設定します。
例
-
レスポンスを作成する:
func handler(w http.ResponseWriter, r *http.Request) { // ステータスコードを設定 w.WriteHeader(http.StatusOK) // ヘッダーを設定 w.Header().Set("Content-Type", "text/html; charset=utf-8") // レスポンスボディにデータを書き込む w.Write([]byte("<h1>Hello, World!</h1>")) }
ポイント
-
w
を使って、クライアントに送り返す内容を作成します。 - 必要に応じてヘッダーやステータスコードを設定し、レスポンスをカスタマイズします。
総合的な流れの理解
-
リクエスト受信:
ユーザーがウェブページにアクセスすると、その情報が
r *http.Request
としてサーバーに届きます。 -
リクエストの解析:
ハンドラー関数内で、
r
を使ってリクエストの詳細(URL、メソッド、ヘッダーなど)を確認します。 -
必要な処理の実行:
リクエストに応じて、データベースから情報を取得したり、計算したりします。
-
レスポンスの準備:
処理結果を
w http.ResponseWriter
を使ってレスポンスとして書き込みます。 -
レスポンス送信:
サーバーは
w
に書き込まれた内容をクライアントに送り返します。
別の例え:郵便のやり取り
- クライアント(ユーザー):手紙を送る人
- サーバー:郵便局
-
r *http.Request
(受け取った手紙):- 送り主の住所
- 宛先の住所
- 手紙の内容
-
w http.ResponseWriter
(返事を書くための封筒と紙):- 封筒に宛先を書く
- 手紙の内容を書く
流れ
- 手紙(リクエスト)が郵便局(サーバー)に届く。
- 郵便局員(ハンドラー関数)が手紙(
r
)を読み、内容を理解する。 - 必要な情報を調べたり、手続きを行う。
- 返信用の手紙(
w
)を作成し、内容を書き込む。 - 完成した手紙を送り返す。
まとめ
-
r *http.Request
はクライアントからの「依頼書」や「注文書」:- ユーザーが何を求めているかの情報が詰まっています。
- これを読むことで、サーバーは適切な対応ができます。
-
w http.ResponseWriter
はサーバーからの「返答用紙」や「商品を乗せるトレイ」:- ユーザーに返す情報やデータを書き込みます。
- これを通じて、サーバーはユーザーに結果を伝えます。
実際のコードでの使用例
func helloHandler(w http.ResponseWriter, r *http.Request) {
// リクエストのパスを取得
path := r.URL.Path
// レスポンスヘッダーを設定
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
// レスポンスボディに書き込む
fmt.Fprintf(w, "あなたがアクセスしたパスは: %s", path)
}
-
解説:
-
r.URL.Path
を使って、ユーザーがアクセスしたパスを取得します。 -
w.Header().Set
で、レスポンスのヘッダー情報を設定します。 -
fmt.Fprintf(w, ...)
で、レスポンスボディに情報を書き込みます。
-