Skip to content

Instantly share code, notes, and snippets.

@yosuke-furukawa
Last active May 4, 2021 18:39
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yosuke-furukawa/8309096 to your computer and use it in GitHub Desktop.
Save yosuke-furukawa/8309096 to your computer and use it in GitHub Desktop.

GolangでWebAppを作るとき

GolangでWebアプリを作るときのまとめ。三回に分けて実施します。 初回と二回目はpureなgolangのコアモジュールを使って書いてみます。 初回はhttpモジュールについて二回目はDBを使った適当なWebAppを作ります。 三回目はrevelというgolangでは有名なWAFを使って書いてみます。

http.ListenAndServe

まずはこのfuncを覚えましょう。 ListenAndServeは以下の様な構成を持ちます。

ListenAndServe

ListenAndServeはサーバを起動して、ハンドラを登録するための関数。

第一引数にアドレスを、第二引数にハンドラを指定します。第二引数には基本的にnilを指定します。 一旦第二引数に関しては無視してください。 あとで説明します。

package main

import "net/http"

func main() {
  http.ListenAndServe(":8080", nil)
}
$ go run src/main/main.go
$ curl http://localhost:8080/
=> 404 page not found

当然ながら何もレスポンスを返さないので、404 page not found が返ります。

http.HandleFunc

ハンドラを登録して何かレスポンス返してみましょう。 リクエストやレスポンスを操作する関数として、HandleFunc関数があります。

HandleFunc関数は第一引数にhttp.ResponseWriterを取り、第二引数に*http.Requestを受け取ります。

第一引数のResponseWriterがResponseを表しています。

ResponseWriter

第二引数のRequestを表しています。

Request

package main

import (
	"io"
	"net/http"
)

// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "hello, world!\n")
}

func main() {
  http.HandleFunc("/hello", HelloServer)
	http.ListenAndServe(":8080", nil)
}
$ curl http://localhost:8080/
=> 404 page not found
$ curl http://localhost:8080/hello
=> hello, world!

http.Requestの情報を元にレスポンスを変えてみる

http.Requestはこんな構造

type Request struct {
        Method string // GET, POST, PUT, etc.

        URL *url.URL

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

        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
}

んで、今回は、net/url.URLを使って動的なレスポンスを実現してみる。 URLはこんな構造。

type URL struct {
        Scheme   string
        Opaque   string    // encoded opaque data
        User     *Userinfo // username and password information
        Host     string    // host or host:port
        Path     string
        RawQuery string // encoded query values, without '?'
        Fragment string // fragment for references, without '#'
}

各値は

scheme://[userinfo@]host/path[?query][#fragment]

に相当。

サーバーを変更。Pathに応じてhelloに続く文字列が変わるようにした。

package main

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

// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
	hello := fmt.Sprintf("hello, %q\n", req.URL.Path)
	io.WriteString(w, hello)
}

func main() {
	http.HandleFunc("/", HelloServer)
	http.ListenAndServe(":8080", nil)
}
$ curl http://localhost:8080/dena
=> hello, "/dena"

デフォルトハンドラを登録する

ListenAndServeの第二引数がnilの場合、HandlerFuncなどで登録したHandlerが使われるが、第二引数にHandlerを指定した場合はそれがデフォルトのハンドラになり、以降ハンドラの追加、変更はできなくなる。

package main

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

// hello worldだけ話す関数
func HelloServer1(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "hello, world!\n")
}

// hello %pでパスを話す関数
func HelloServer2(w http.ResponseWriter, req *http.Request) {
	hello := fmt.Sprintf("hello, %q\n", req.URL.Path)
	io.WriteString(w, hello)
}

// DefaultHanderにするためのstruct
type AppHandler struct {
    appName string
}

// HandlerはServeHTTPメソッドを実装する実体
func(index *AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "hello, %s!", index.appName)
}

func main() {
	http.HandleFunc("/v1/", HelloServer1)
	http.HandleFunc("/v2/", HelloServer2)
  index := new(AppHandler)
  index.appName = "sample app"
	http.ListenAndServe(":8080", index)
}
$ curl http://localhost:8080/v1/
=> hello, sample app
$ curl http://localhost:8080/v2/abc
=> hello, sample app
$ curl http://localhost:8080/
=> hello, sample app

reference

http://golang.org/pkg/net/http/

http://qiita.com/tenntenn/items/061e3bdf37e1a2454fbf

http://qiita.com/udzura/items/39e6b927d6d17f76df06

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment