Go言語を学び始めたときnet/httpを使って簡単なものを作ったりしていましたが、echoを使ったプロジェクトに参画してから触れることなく過ごしてきました。
しかしGoでオススメのWebフレームワークを聞かれることが多い を読んで「net/http」についてもうちょっと勉強しようと思い、HTTPサーバー実装について簡単にまとめました。
「net/http」パッケージはHTTPクライアントとサーバーの実装を提供していて、GET、POSTリクエスト、Formデータの送信など色々できます。
が、今回はHTTPサーバーを実装する上で基礎となる部分に絞っています。
こんなこと書くと元も子もないですが、パッケージの公式ドキュメントがしっかりしているのでそちらを読んで頂いた方が良い!笑。
net/httpパッケージ概要
net/httpパッケージはHTTPクライアントとサーバーの実装を提供する。
HTTPサーバー実装の概要を掴むのに重要なのはListenAndServe
、Handle
、HandleFunc
の3つの関数とHandler
インターフェース。
func ListenAndServe(addr string, handler Handler) error
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func Handle(pattern string, handler Handler)
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
概要
- ListenAndServe にアドレスとハンドラーを渡せばHTTPサーバーを起動させることができる。
- 指定されたTCPネットワークアドレスでリッスンして、ハンドラーを使って Serve を呼び出してHTTP接続を受け入れる。
- ハンドラーは通常 nil 。(デフォルトのハンドラー DefaultServeMux を使用)
- HandleFunc と Handle は指定したパターンのハンドラー関数を DefaultServeMux に登録する
- Hanler はインターフェース。 ServeHTTP 関数が実装されていればOK
例
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
log.Fatal(http.ListenAndServe(":8080", nil))
Server
s := &http.Server{
Addr: ":8080",
Handler: myHandler,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
要は
ポイント
- ListenAndServe でHTTPサーバー起動
- ListenAndServeにはアドレスを渡す。ハンドラーは通常nilでOK。デフォルトの DefaultServeMux が使われる
- HandleFunc もしくは Handle を使って DefaultServeMux に指定したURLパターンのときに実行されるハンドラー関数を登録
ListenAndServeでHTTPサーバー起動、ハンドラー関数(各URLへアクセスが来たときの処理)をHandleFunc か Handle で登録するってこと。
次は HandleFunc と Handle を使ったハンドラー関数の登録方法について書いていきます。
DefaultServeMuxって何ってのは余裕があれば別途まとめます
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
// URLのパターンとハンドラーを渡す
http.HandleFunc("/foo", fooHandlerFunc)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
// `/foo` へリクエストがきたときに実行されるハンドラー
// http.ResponseWriterにコンテンツを書き込む。
// もちろんHTMLテンプレートを使ったりJSONを返すことも可能
func fooHandlerFunc(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "/fooページです!!")
}
main.go ファイルに↑のコードを書いて go run main.go
を実行、ブラウザでhttp://localhost:8080/foo
にアクセスすると
func Handle(pattern string, handler Handler)
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Handle は上記のようにURLパターンと Handler を引数に持ちます。
そして Handler はインターフェースで ServeHTTP メソッドが実装されている必要があります。
なので ServeHTTP メソッドを持つ型を用意して、それを Handle関数にわたしてあげればOK!
package main
import (
"fmt"
"log"
"net/http"
)
type myHandler struct{}
// myHandlerがHandlerインターフェースに適合するようにServeHTTPメソッドを実装
func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "/fooページ by myHandler!!")
}
func main() {
// myHandlerを渡す
http.Handle("/foo", &myHandler{})
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
main.go ファイルに↑のコードを書いて go run main.go
を実行、ブラウザでhttp://localhost:8080/foo
にアクセスすると