2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

(go lang) HandleFunc のメモ / APIコード解読 その1

Last updated at Posted at 2017-01-26

0. 超シンプルなAPIのコードを読む

main.go
package main

import (
	"fmt"
	"html"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
	})

	log.Fatal(http.ListenAndServe(":8080", nil))
}
  • go run main.goで実行
  • ブラウザでlocalhost:8080を叩く。

1. 解読メモ

1-1. http.HandleFunc

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
  • handlerを定義し、ServerMuxに登録する関数.
    • handler : (リクエストURLのパターンマッチと、マッチしたリクエストに対する応答が定義)
    • ServerMux : (パターンマッチで適合したリクエストに対して、そのパターンマッチを持つhandlerを呼び出してくれる)

1-2. http.ResponseWriter

  • リクエストに対するレスポンスを作るためのインターフェース

1-3. *http.Request

  • Serverが受け取ったhttpリクエストを扱うためにnet/httpパッケージで用意されている構造体

1-4. http.ListenAndServe

func ListenAndServe(addr string, handler Handler) error
  • 第1引数で指定された[TCPアドレス:ポート]をListenし、第2引数で指定したhandlerを提供する。
  • 上述のコードのように、handlerがnilを指定された場合はデフォルトのServerMuxが使われる。

2. 書き換え

  • 以上を踏まえて次のように書き換えてみる

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", fooooServer)
	log.Fatal(http.ListenAndServe(":8080", nil))

}

func fooooServer(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}

  • 単にhandlerに名前(fooooServer)を付けて、別途取り出してみただけ。でもコードが長くなる時などはこっちの方が分かりやすそう。。

3. その他のメモ、疑問解決

3-1. ResponseWriterインターフェースに値を入れるときに、fmt.Fprintfが使えるのはどうして?

  • ResponseWriterの説明を読むと、以下のようになっている
type ResponseWriter interface {
    Header() Header
    Write([]byte) (int, error)
    WriteHeader(int)
}

なので、素直に考えると、

 fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))

ではなくて

w.Write([]byte("hello, " + r.URL.Path))

となる。
しかし、例えばstackoverflowのこのページでも議論されているように、Fprintfの第1引数はio.Writerというインタフェースが使われていて、これは以下のような作りになっているらしい。

type Writer interface {
    Write(p []byte) (n int, err error)
}

つまりバイト型のスライスからstringへの変換は自動でやってくれるからfmt.Fprintfなどを使った方がベターなんだと。

3-2. Request構造体を見学

  • サンプルをいじってRequest構造体を構成する要素を色々出力させて見る
type Request struct {
        // For client requests an empty string means GET.
        Method string

        // URL specifies either the URI being requested (for server
        // requests) or the URL to access (for client requests).
        URL *url.URL

        // The protocol version for incoming server requests.
        Proto      string // "HTTP/1.0"
        ProtoMajor int    // 1
        ProtoMinor int    // 0

        // Header contains the request header fields either received
        // by the server or to be sent by the client.
        Header Header

        // Body is the request's body.
        Body io.ReadCloser
        ContentLength int64
        TransferEncoding []string
        Close bool
        Host string

        Form url.Values
        PostForm url.Values
        MultipartForm *multipart.Form
        Trailer Header
        RemoteAddr string
        RequestURI string
        TLS *tls.ConnectionState
        Cancel <-chan struct{}
        Response *Response
}

たくさんある。

 fmt.Fprintf(w, "%q", html.EscapeString(r.Proto))
// HTTP/1.1と出る
 fmt.Fprintf(w, "%q", html.EscapeString(r.Method))
// GETと出る。リクエストメソッドがnilだったらGETだと解釈している

Headerはmap構造になっている。

 fmt.Fprintf(w, "%q", html.EscapeString(Header["Accept-Language"]))
// [en-US,en;q=0.5]と出る。
 fmt.Fprintf(w, "%q", html.EscapeString(Header["Cache-Control"]))
// [max-age=0]と出る。
 fmt.Fprintf(w, "%q", html.EscapeString(r.Close))
// falseと出る。レスポンスを返した後もコネクションクローズしない。
 fmt.Fprintf(w, "%q", html.EscapeString(r.RequestURI))
// '/'と出る
 fmt.Fprintf(w, "%q", html.EscapeString(r.Host))
// localhost:8080と出る
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?