かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Go プログラミング実践入門を読みながら Go での Web App のハローワールド

先ほど脱線して http のクライアント側の機能に走ってしまったので気を取り直してサーバー側に行きたいと思います。

といってもハローワールドするだけなら凄く簡単。本当に凄く

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(res, "Hello world")
    })
    http.ListenAndServe(":8080", nil)
}

HandleFunc でハンドラーを登録して ListenAndServe で待つ。以上終了。できた。

f:id:okazuki:20181031222105p:plain

試しに http://localhost:8080/hoge/foo?bar=puyopuyo を叩いてハンドラーの関数にブレークポイントはってリクエストの構造体の中身を見てみた。

f:id:okazuki:20181031222352p:plain

当然と言えば当然だけど基本的なものは詰まってるので、後は頑張ればいけそう。

ちなみにパスに対して何かしらするものを登録するのは HandleFunc の他に Hundle というのがあるみたい。 Handle には以下のような Handler インターフェースを渡す。

type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}

つまり、さっきのをこれを使う用に書き直すとこんな感じ。

package main

import (
    "fmt"
    "net/http"
)

type MyHandler struct {
}

func (*MyHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(res, "Hello world!! Handler version.")
}

func main() {
    http.Handle("/", &MyHandler{})
    http.ListenAndServe(":8080", nil)
}

今回は MyHandler がデータを何も持ってない構造体なので、何も嬉しくないけど設定情報とかを持たせれる点で HandleFunc より柔軟そう。

現に以下の FileServer 関数の例では http.FileServer を使って特定ディレクトリの下のファイルを返すようにしてるみたい。

https://golang.org/pkg/net/http/#FileServer

試しに以下のコードを動かすと C:\Work の下のファイルを返してくれるようになった。

package main

import (
    "fmt"
    "net/http"
)

type MyHandler struct {
}

func (*MyHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(res, "Hello world!! Handler version.")
}

func main() {
    http.Handle("/", http.FileServer(http.Dir("/work")))
    //http.Handle("/", &MyHandler{})
    http.ListenAndServe(":8080", nil)
}

f:id:okazuki:20181031224404p:plain

http.FileServer 関数で作ったやつは、素直にパスをみてファイルを返してくれるみたいなので/static/ とかにマッピングすると C:\Work の下にも static フォルダを切らないと NotFound になる。 基本的には、パスから static を外して欲しいから、そこらへんのことをしてくれると思われるのが http.StripPrefix 関数。こんな感じでいける。

package main

import (
    "fmt"
    "net/http"
)

type MyHandler struct {
}

func (*MyHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(res, "Hello world!! Handler version.")
}

func main() {
    http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("/work"))))
    http.Handle("/", &MyHandler{})
    http.ListenAndServe(":8080", nil)
}

これで http://localhost:8080/static/hello.txt にアクセスすると c:\work\hello.txt の中身が返ってくるし、http://localhost:8080/hogehoge みたいなのにアクセスすると MyHandler のほうに処理がいく。

結構単純でいいね。