2015年10月19日月曜日

Go langのnet/httpでHTTPサーバーを立てる

Go langは、簡単にウェブサーバを立てられるという話を聞いたので、ウェブサーバを立ててみます。
ここでは、Go langのhttpパッケージを使いました。

Hello, World
まずは、簡単に"Hello, World"を返すサーバです。
package main

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

// http.HandleFuncに登録する関数
// http.ResponseWriterとhttp.Requestを受ける
func HelloServer(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, World\n")
}

func TestServer(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "TEST\n")
}

func main() {
    // http.HandleFuncにルーティングと処理する関数を登録
    http.HandleFunc("/", HelloServer) 
    http.HandleFunc("/test", TestServer)

    // ログ出力
    log.Printf("Start Go HTTP Server")

    // http.ListenAndServeで待ち受けるportを指定
    err := http.ListenAndServe(":4000", nil)

    // エラー処理
    if err != nil {
       log.Fatal("ListenAndServe: ", err)
    }
}
go run
サーバスタート
$ go run web.go
2015/10/19 16:55:08 Start Go HTTP Server

HTTPレスポンスを確認
$ curl localhost:4000
Hello, World
$ curl localhost:4000/test
TEST

同じサーバをスタートすると。既にポートを使っているのでエラー。
$ go run web.go
2015/10/19 16:55:18 Start Go HTTP Server
2015/10/19 16:55:18 ListenAndServe: listen tcp :4000: bind: address already in use
exit status 1

html/template
GoのHTMLテンプレートにはメジャーどころとして text/templatehtml/template があるらしいです。
ここでは、html/templateパッケージを利用して、テンプレートファイルを読み込んで出力します。こちらの方がセキュアなHTMLを生成するそうです。
テンプレートは、親テンプレートと小テンプレートの2つを用意しました。
現在時刻を表示する単純なウェブページを作ります。
時刻オブジェクトを文字列に変換するときは、fmt.Sprint(hoo)を使いました。
ほかにも、文字・数値変換にはstrconvパッケージも使えます。この場合は、パッケージをインポートして、unixtime := strconv.FormatInt(time.Now().Unix(), 10)というふうに書きます。これはどちらかと言うと、2進数表現にしたい時など、細かい用途に使うのかな?と思いました。
web.go
package main

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

type TemplateData struct {
    Title string
    Datetime string
    Unixtime string
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
    // 親テンプレートindex.htmlと、小テンプレートbody.htmlを用意
    tmpl := template.Must(template.ParseFiles("views/index.html", "views/body.html"))

    // タイトル
    title := "現在の時刻"

    // bodyに表示するコンテンツ
    // 時刻オブジェクトを文字列に変換
    datetime := fmt.Sprint(time.Now())
    unixtime := fmt.Sprint(time.Now().Unix())

    // テンプレートを実行して出力
    templatedata := TemplateData{title, datetime, unixtime}
    if err := tmpl.ExecuteTemplate(w, "base", templatedata); err != nil {
        fmt.Println(err)
    }
}

func main() {
    http.HandleFunc("/", HelloServer)
    log.Printf("Start Go HTTP Server")
    err := http.ListenAndServe(":4000", nil)
    if err != nil {
       log.Fatal("ListenAndServe: ", err)
    }
}
views/index.html
{{define "base"}}
<html>
    <head>
        <meta charset="utf-8">
        <title>{{.Title}}</title>
    </head>
    <body>
        {{template "body" .}}
    </body>
</html>
{{end}}
views/body.html
{{define "body"}}
    <dev id="content">
        <p>Datetime: {{.Datetime}}</p>
        <p>Unixtime: {{.Unixtime}}</p>
    </dev>
{{end}}
go run
$ go run web.go
2015/10/20 09:57:18 Start Go HTTP Server
$ curl localhost:4000
<html>
    <head>
        <meta charset="utf-8">
        <title>現在の時刻</title>
    </head>
    <body>

    <dev id="content">
        <p>Datetime: 2015-10-20 09:57:19.297331721 &#43;0900 JST</p>
        <p>Unixtime: 1445302639</p>
    </dev>

    </body>
</html>

なにか色々できそうな気がしてきますね。


参考文献)
http - The Go Programming Language
https://golang.org/pkg/net/http/
A Tour of Go Web servers
http://go-tour-jp.appspot.com/#57
Go言語によるwebアプリの作り方
http://www.slideshare.net/yasi_life/goweb-16448500
Codelab: Webアプリケーションを書いてみよう - golang.jp
http://golang.jp/codelab-wiki
テンプレートの処理 | build-web-application-with-golang
https://astaxie.gitbooks.io/build-web-application-with-golang/content/ja/07.4.html
逆引きGolang (日付と時刻)
http://ashitani.jp/golangtips/tips_time.html
Golangでの文字列・数値変換 - 小野マトペの納豆ペペロンチーノ日記
http://matope.hatenablog.com/entry/2014/04/22/101127

Title image from Alyson Hurt
The Go gopher was designed by Renee French. http://reneefrench.blogspot.com/