LoginSignup
0
0

More than 1 year has passed since last update.

Go標準パッケージを利用したリクエスト・レスポンスの処理

Posted at

net/http

この記事ではGoの標準パッケージであるnet/httpを利用したリクエスト、レスポンスの処理の方法について解説する。
Goプログラミング実践入門 標準ライブラリでゼロからWebアプリを作る」という書籍を参考にしており、この書籍のまとめでもある。

リクエストの受信

ListenAndServe

GoにおいてHTTPサーバーを起動させるためのメソッド。
第一引数:ネットワークアドレス。「””」を指定した場合、80番ポートになる。
第二引数:リクエストを処理するハンドラ。nilを指定した場合、DefaultServeMuxが使われる。

server.ListenAndServe(ネットワークアドレス, ハンドラ)

server構造体を使ってサーバーの設定ができる。ネットワークアドレスやハンドラもこの中で指定できるので、これを使った場合引数はいらない。

type Server struct {
	Addr string
	Handler Handler
	TLSConfig *tls.Config
	ReadTimeout time.Duration
	ReadHeaderTimeout time.Duration
	WriteTimeout time.Duration
	IdleTimeout time.Duration
	MaxHeaderBytes int
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
	ConnState func(net.Conn, ConnState)
	ErrorLog *log.Logger
	BaseContext func(net.Listener) context.Context
	ConnContext func(ctx context.Context, c net.Conn) context.Context
}

こんな感じで使う。

func main() {
	server := http.Server{
		Addr:    "127.0.0.1:8080",
		Handler: nil,
	}
	server.ListenAndServe()
}

ハンドラの設定

GoにおけるハンドラとはServeHTTPといいメソッドを持ったインターフェースのこと。
ServeHTTPh第一引数にインターフェースHTTPResponseWriter、第二引数に構造体Requestへのポインタを取る。

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

http.Handle

http.Handle()というメソッドを使ってハンドラーの設定ができる。以下が使用例。

package main

import (
	"fmt"
	"net/http"
)

type HelloHandler struct{}

func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

type WorldHandler struct{}

func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}

func main() {
	hello := HelloHandler{}
	world := WorldHandler{}

	server := http.Server{
		Addr: "127.0.0.1:8080",
	}

	http.Handle("/hello", &hello)
	http.Handle("/world", &world)

	server.ListenAndServe()
}

ポイント

  • URLごとにハンドラーを用意する。この場合はHelloHandler{}WorldHandler{}を用意している。
  • server構造体のHandlerフィールドは設定しない。
  • http.Handle()を使うことでURLごとのハンドラーを設定する。以下のように使う。
http.Handle(URL, ハンドラーへのポインタ)

http.HandleFunc

http.HandleFunc()というメソッドを利用してハンドラーを設定することもできる。
http.HandleFunc()を使うとわざわざ構造体を宣言することなく、関数を生成するだけでハンドラーの設定ができる。
以下が使用例。

package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello!")
}

func world(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "World!")
}

func main() {
	server := http.Server{
		Addr: "127.0.0.1:8080",
	}
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/world", world)

	server.ListenAndServe()
}

ポイント

  • http.HandleFunc()は第一引数にURLを、第二引数に関数名を渡す。渡された名前の関数がハンドラーに変換される。
http.HandleFunc(URL, 関数名)

レスポンスの送信

ResponseWriter

レスポンスを送信するために利用するインターフェース。

Write

HTTPレスポンスのボディに書き込むメソッド。以下の例ではHTMlを書き込む。

func writeExample(w http.ResponseWriter, r *http.Request) {
	str := `<html>
	<head><title>Go Web Programming</title></head>
	<body><h1>Hello World</h1></body>
	</html>`
	w.Write([]byte(str))
}

レスポンスは以下のようになる。

$ curl -i 127.0.0.1:8080/write
HTTP/1.1 200 OK
Date: Wed, 23 Nov 2022 02:02:53 GMT
Content-Length: 95
Content-Type: text/html; charset=utf-8

<html>
<head><title>Go Web Programming</title></head>
<body><h1>Hello World</h1></body>
</html>%

ポイント

  • レスポンスのボディに書き込むにはバイト配列である必要がある。

WriteHeader

HTTPレスポンスのステータスコードを書き込む。

func writeHeaderExample(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(501)
	fmt.Fprintln(w, "エラーレスポンスです。")
}

レスポンスは以下のようになる。ステータスコードとして501を返せていることがわかる。

$ curl -i 127.0.0.1:8080/writeheader
HTTP/1.1 501 Not Implemented
Date: Wed, 23 Nov 2022 02:15:37 GMT
Content-Length: 34
Content-Type: text/plain; charset=utf-8

エラーレスポンスです

ポイント

  • このメソッドを呼び出した後はヘッダに書き込むことはできない。ResponseWriterに書き込むことはできる。
  • このメソッドを呼び出さない場合、ステータスは「200 OK」になる。

Header

ヘッダーと転送先URLを書き込む。

w.Header().Set()の形で使う。第一引数にヘッダーのキー名、第二引数に値を書く。

func headerExample(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Location", "http://google.com")
	w.WriteHeader(302)
}

レスポンスは以下のようになる。

$ curl -i 127.0.0.1:8080/redirect   
HTTP/1.1 302 Found
Location: http://google.com
Date: Wed, 23 Nov 2022 02:24:21 GMT
Content-Length: 0

ブラウザで127.0.0.1:8080/redirectにアクセスするとGoogleに転送される。
スクリーンショット 2022-11-23 11.26.18.png

ポイント

  • w.Header().Set()w.WriteHeader()よりも先に書く必要がある。

JSONを返す

Postという構造体を利用してJSONを返すとする。

type Post struct {
	User    string
	Threads []string
}

以下のように関数を定義する。

func jsonExample(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	post := &Post{
		User:    "Goromaru",
		Threads: []string{"1try", "2try", "3try"},
	}
	json, _ := json.Marshal(post)
	w.Write(json)
}

レスポンスはこのように返ってくる。

$ curl -i 127.0.0.1:8080/json    
HTTP/1.1 200 OK
Content-Type: application/json
Date: Wed, 23 Nov 2022 02:37:30 GMT
Content-Length: 52

{"User":"Goromaru","Threads":["1try","2try","3try"]}%

ポイント

  • まず最初にw.Header().Set()を利用してコンテンツタイプを「application/json」に設定する。
  • その後、Post構造体のインスタンスpostを作成する。
  • json.Marshal()を利用してJSONを生成する。
  • w.Write()を利用してボディに書き込む。
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