Go言語

【Go言語】net/httpパッケージの基本的なことまとめ(シンプルなHTTPサーバー実装)

Go言語を学び始めたときnet/httpを使って簡単なものを作ったりしていましたが、echoを使ったプロジェクトに参画してから触れることなく過ごしてきました。

しかしGoでオススメのWebフレームワークを聞かれることが多い を読んで「net/http」についてもうちょっと勉強しようと思い、HTTPサーバー実装について簡単にまとめました。

「net/http」パッケージはHTTPクライアントとサーバーの実装を提供していて、GET、POSTリクエスト、Formデータの送信など色々できます。

が、今回はHTTPサーバーを実装する上で基礎となる部分に絞っています

 

こんなこと書くと元も子もないですが、パッケージの公式ドキュメントがしっかりしているのでそちらを読んで頂いた方が良い!笑。

 

net/httpパッケージ概要

net/httpパッケージはHTTPクライアントとサーバーの実装を提供する。

HTTPサーバー実装の概要を掴むのに重要なのはListenAndServeHandleHandleFuncの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って何ってのは余裕があれば別途まとめます

 

HandlerFunc でのハンドラー関数の登録

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

 

HandleFunc にはURLパターンと関数をわたしてあげれば良いので↓のようにするだけ。


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にアクセスすると

Handleでのハンドラー関数の登録


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にアクセスすると

イチオシ記事

1

自己紹介 フリーランスエンジニアをしているヨノと申します。 独学でプログラミングを学び、ソシャゲ・SaaS開発などを経て、2018年からフリーランスエンジニアとして活動しています。 主にバックエンド中 ...

2

はじめまして、フリーランスエンジニアのヨノと申します。 自己紹介 独学でプログラミングを学び、ソシャゲ・SaaS開発などを経て、2018年からフリーランスエンジニアとして活動しています。 主にバックエ ...

3

ネット上で色々言われているフリーランスエンジニア....。「本当はどうなの?」と思っている人は多いでしょう。 そこで本記事ではフリーランスエンジニア5年生の私が、ネット上の意見も引用しながら実態を解説 ...

-Go言語