勉強部屋‎ > ‎Go 1‎ > ‎

演習a3

httpパッケージについて,極々単純なWebアプリケーションで演習します.

演習(補足:httpパッケージ) 

(1)
  • Webブラウザからアクセスすると,"こんにちは,世界!"という文字列と,URLのパスを表示するhttpサーバ(Webサーバ)を作成せよ.このサービスのポートは123456とする.
  • 例えば,http://localhost:123456/abc にアクセスすると,"こんにちは,世界! abc" と表示する.
(2)
  • Webブラウザからアクセスすると,サーバのファイルシステムの内容を表示するhttpサーバ(Webサーバ)を作成せよ.
  • 例えば,http://localhost:123456/index.html にアクセスすると,サーバの実行ディレクトリにあるindex.htmlを表示する.
  • 例えば,http://localhost:123456/fixed/ にアクセスすると,サーバの実行ディレクトリのサブディレクトリfixedの情報を表示する.
(3)
  • 次のようなhttpサーバ(Webサーバ)を作成せよ.
  • http://localhost:123456/J にアクセスすると,"こんにちは,世界!" と表示する.
  • http://localhost:123456/E にアクセスすると,"Hello, World!" と表示する.
  • http://localhost:123456/R/* にアクセスすると(R/の後にどのような文字列があっても),http://localhost:123456/J にリダイレクトする.すなわち,"こんにちは,世界!" と表示する.
  • http://localhost:123456/fixed/* にアクセスすると,サーバの実行ディレクトリのサブディレクトリfixedの情報を表示する.
  • それ以外のURLでアクセスすると,エラーを表示する.

解答例(1)

  1. package main
  2. import (
  3.     "fmt"
  4.     "net/http"
  5.     "log"
  6. )
  7.  
  8. func helloHandler(w http.ResponseWriter, r *http.Request) {
  9.     fmt.Fprintf(w, "こんにちは,世界! %s", r.URL.Path[1:])
  10. }
  11.  
  12. func main() {
  13.     http.HandleFunc("/", helloHandler)
  14.     log.Fatal(http.ListenAndServe(":12345",nil))
  15. }

解説(1)

net/httpパッケージは,拡張可能なHTTPサーバと基本的なHTTPクライアントを提供します.

概要
  • 13行目のhttp.HandleFuncで,Webのルート"/"における全てのリクエストをhelloHandlerで処理することを登録しています.
  • 14行目のhttp.ListenAndServeで,ポート123456でのリクエストの受付を開始しています.
  • 8行目のHelloHandler関数はhttp.HandlerFunc型で,http.ResponseWriteとhttp.Requestを引数として取ります.http.ResponseWriterに書き込むことによってHTTPサーバのレスポンスが生成され,HTTPクライアントにデータが送信されます.
  • http.RequestはHTTPリクエストを格納したデータ構造です.文字列r.URL.Pathは,リクエストのパス部分です.[1:]によって,最初の一文字「/」を除去した部分文字列(スライス)を作成し,それを表示するようにしています.
  • URL http://localhost:10080/golang にアクセスすると「こんにちは世界! golang」と表示されます. 
関数,メソッド,型の説明
  • func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
    • DefaultServeMuxのパターン(第1引数patternで指定)に対しハンドラ関数(第2引数handlerで指定)を登録します.DefaultServeMuxは,デフォルトのHTTPリクエストのマルチプレクサです.登録されているパターンのリストと各リクエストのURLを比較し,URLと最も一致するパターンに登録されているハンドラを呼び出す.
    • 第1引数のpatternは/で始まる必要があります.
    • "/favicon.ico"のようにスラッシュで終わらないパターンは固定パスを表し,"/images/"のようにスラッシュで終わるパターンはサブツリーを表します.
    • 長いパターンは短いパターンより優先されます.例えば,"/images/"として登録されたハンドラと,"/images/thumbnails/"として登録されたハンドラがあるとき,"/images/thumbnails/"で始まるパス("/images/thumbnails/thum001.gif"など)は後者のハンドラが呼び出され,それ以外の"/images/"サブツリーへのパス("images/001.gif"など)では前者が呼び出されます.
  • func ListenAndServe(addr string, handler Handler) os.Error
    • TCPネットワークアドレスaddrでリッスンし,HTTP接続を受け付けると,それぞれに新しいサービススレッドを作成します.
    • このサービススレッドはリクエストを読み込み,それに応答するためにhandlerを呼び出します.handlerは通常nilであり,このときはDefaultServeMuxが使われます.
Request型,URL型

type Request struct {
    Method     string // GET, POST, PUTなど。
    RawURL     string // リクエストで使われた生のURL。
    URL        *URL   // 解析済みURL。
    Proto      string // "HTTP/1.0"
    ProtoMajor int    // 1
    ProtoMinor int    // 0
    Header map[string]string  // リクエストの行を値にマップ
    Body io.ReadCloser        // メッセージのボディ
    ContentLength int64       // コンテンツの長さ
    TransferEncoding []string // 転送に使われたエンコーディングのリスト
    Close bool        // 応答後に接続を閉じるかどうか
    Host string       // URLによって要求されたホスト
    Referer string    // 参照元URL
    UserAgent string  // 「User-Agent:」ヘッダの文字列
    Form map[string][]string  // 解析済みフォーム
    Trailer map[string]string // トレーラーのキーを値にマップ
}

type URL struct {
    Raw          string // 元の文字列
    Scheme       string // スキーマ
    RawAuthority string // [userinfo@]host
    RawUserinfo  string // ユーザ情報
    Host         string // ホスト
    RawPath      string // /path[?query][#fragment]
    Path         string // /path
    OpaquePath   bool   // パスが不明確 (スキーマが指定されたのにルートからのパスでない)
    RawQuery     string // クエリ
    Fragment     string // フラグメント
}


func Fatal(v ...interface{})
  • log.Fatalは,Print()のあとにos.Exit(1)を呼び出すことと同じです.
  • os.Exitは,ステータスコードとともにカレントのプログラムを終了させます.ステータスコードは0のとき成功,それ以外の時エラーを表します.

解答例(2)

  1. package main
  2. import (
  3.     "net/http"
  4.     "log"
  5. )
  6.  
  7. func main() {
  8.     http.Handle("/", http.FileServer(http.Dir(".")))
  9.     log.Fatal(http.ListenAndServe(":12345",nil))
  10. }

解説(2)

概要
  • 8行目のhttp.Handleで,Webのルート"/"における全てのリクエストをhttp.FileServerで処理することを登録しています.
  • 9行目のhttp.ListenAndServeで,ポート123456でのリクエストの受付を開始しています.
  • 8行目のhttp.FileServer関数はHandler型で,カレントディレクトリ"."をルート"/"とするファイルシステムの内容を返すハンドラを返します.
  • これによって,このサーバを実行したディレクトリをWebのルートとするWebサーバとなります.
  • URL http://localhost:123456/ にアクセスすると,カレントディレクトリの内容が表示されます.
関数の説明

func Handle(pattern string, handler Handler)
  • Handleは、DefaultServeMuxのpatternに対しhandlerを登録します。
  • (1)のHandleFuncと同じ機能です.違いは第2引数です.HandleFunc関数はfunc(ResponseWriter, *Request)型を引数にとりますが,Handle関数はHandler型を引数にとります.
  • パッケージには,FileServer,NotFoundHandler,RedirectHandlerというハンドラーを返す関数が定義されています. 
func FileServer(root, prefix string) Handler
  • HTTPリクエストに対し,rootを起点とするファイルシステムの内容を返すハンドラを返します. 
func NotFoundHandler() Handler
  • 各リクエストに対して“404 page not found”を返すだけの単純なリクエストハンドラを返します.
func RedirectHandler(url string, code int) Handler
  • 各リクエストに対して与えられたurlとステータスコードでリダイレクトを行うリクエストハンドラを返します.

解答例(3)

  1. package main
  2. import (
  3.     "fmt"
  4.     "net/http"
  5.     "log"
  6. )
  7.   
  8. func helloJHandler(w http.ResponseWriter, r *http.Request) {
  9.     fmt.Fprintf(w, "こんにちは,世界!")
  10. }
  11.   
  12. func helloEHandler(w http.ResponseWriter, r *http.Request) {
  13.     fmt.Fprintf(w, "Hello, World!")
  14. }
  15.   
  16. func main() {
  17.     http.HandleFunc("/J", helloJHandler)
  18.     http.HandleFunc("/E", helloEHandler)
  19.     http.Handle("/fixed/", http.FileServer(http.Dir(".")))
  20.     http.Handle("/R/", http.RedirectHandler("/J", 301))
  21.     log.Fatal(http.ListenAndServe(":10080",nil))
  22. }

解説(3)

  • 8行目:helloJHandler:"こんにちは,世界!" と表示するハンドラー.
  • 12行目:helloEHandler:"Hello, World!" と表示する.
  • 17行目:"/J"にアクセスするとhelloJHandlerを呼ぶ.
  • 18行目:"/E"にアクセスするとhelloEHandlerを呼ぶ.
  • 19行目:"/fixed/"にアクセスすると,そのディレクトリのファイルを表示する..FileServerについては,解説(2)を参照.
  • 20行目:"/R/"にアクセスすると,"/J"にリダイレクト.RedirectHandlerについては,解説(2)を参照.301は,指定したリソースが新しいURIに移動したことを表すステータスコード.

ċ
a3-1-http.go
(0k)
Tetsuo Tanaka,
2012/04/29 20:28
ċ
a3-2-http.go
(0k)
Tetsuo Tanaka,
2012/04/29 20:28
ċ
a3-3-http.go
(1k)
Tetsuo Tanaka,
2012/04/29 20:28
Comments