LoginSignup
0
0

[Go言語]簡単なWebサーバの立て方(ListenAndServe関数)

Posted at

今回は初心者向けにGo言語において超簡単なWebサーバを実装します。最終的なコードは最後に載せているので、それだけ見たい方は下まで飛ばしてください!

ListenAndServe関数

http.ListenAndServe関数を用いることでサーバを起動することができます。

http.ListenAndServe(":8080", nil)

http.ListenAndServeの中身を見てみましょう。VSCodeであればfn+F12で関数の定義に飛ぶことができます。もちろん、Githubでも確認できます。

// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

これを見ると、addrとhandlerを使ってhttp.Server構造体を作り、それに対してListenAndServeしているのがわかります。
Addrサーバーアドレス、インターフェースHandlerは一つだけメソッドを定義します。

Handler

2つめの引数Handlerインターフェースは、1つだけメソッドを定義します。

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

ResponseWriter

最初の引数ResponseWriterインターフェースは以下のように3つのメソッドを持ちます。

type ResponseWriter interface {
	Header() Header
	Write([]byte) (int, error)
	WriteHeader(statusCode int)
}

これらのメソッドは以下のように呼び出すことができます。

  1. Header
    • http.Serverのインスタンスを取得し、ヘッダを設定する
  2. WriteHeader
    • statusCodeを設定(200の場合は省略可能)
  3. Write
    • レスポンスボディを設定

*http.Request

2番目の引数*http.Requestは以下のような構造体です。詳細は省きますが、サーバーに送られたリクエストを格納していて、これ使ったらいろいろ取得できるよ、といった認識で大丈夫です。(たぶん...)

type Request struct {
	Method string
	URL *url.URL
	Proto      string // "HTTP/1.0"
	ProtoMajor int    // 1
	ProtoMinor int    // 0
	Header Header
	Body io.ReadCloser
	GetBody func() (io.ReadCloser, error)
	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
	ctx context.Context
}

今回実装するサーバーでは、URLを呼び出して、リクエストに投げられたURLを取得しています。
もしhttp.ListenAndServeの第二引数がnilだった場合は、デフォルトで用意されているDefaultServeMuxが使用されます。

ということで、おさらいをすると

func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}

で定義されたListenAndServeにサーバーアドレスとHandlerを引数にとることでサーバを起動できます。
ここで作られるServer構造体は

type Server struct {
	Addr string
	Handler Handler // handler to invoke, http.DefaultServeMux if nil
	// (以下略)
}

のように、AddrHandlerを持ちます。このServer構造体のインスタンスListenAndServe()を用いて起動します。

// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
	if srv.shuttingDown() {
		return ErrServerClosed
	}
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(ln)
}

サーバの作成

さて、実際にListenAndServe関数を使って起動してみます。

err := http.ListenAndServe(
    ":8080",
    http.HandlerFunc(func (w http.ResponseWriter, r *http.Request)  {
        fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
    }),
)

ここで、http.HandlerFuncを使っています。以下で定義され、ServeHTTPメソッドも用意されています。

type HandlerFunc func(ResponseWriter, *Request)

func (http.HandlerFunc).ServeHTTP(w http.ResponseWriter, r *http.Request)

http.HandlerFuncはGoのhttpパッケージにおいて、任意の関数をhttp.Handlerインターフェースに適合させるための型です。この型は、特定のシグネチャを持つ関数をServeHTTPメソッドを実装したハンドラーとして扱うことを可能にします。これにより、簡単な関数を使用してHTTPリクエストを処理するカスタムハンドラーを素早く作成することができます。

また、

fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])

において、fmt.Fprintf()は内部的にWrite()メソッドを呼び出してレスポンスボディにデータを書き込んでいます。

最終的なコード

golang server.go
package main

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

func main() {
	err := http.ListenAndServe(
		":8080",
		http.HandlerFunc(func (w http.ResponseWriter, r *http.Request)  {
			fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
		}),
	)
	if err != nil {
		fmt.Printf("failed to terminate server: %v", err)
		os.Exit(1)
	}
}

これをターミナル上でgo run server.goとして立ち上げ、別ターミナルで

curl localhost:8080/world

とリクエストを送ってみましょう。
レスポンスとしてHello, world!% が返ってきたら成功です。

0
0
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
0
0