Go言語

【Go言語】net/http ハンドラー関数をラップする

no image
【Go言語】net/httpパッケージの基本的なことまとめ(シンプルなHTTPサーバー実装)

Go言語を学び始めたときnet/httpを使って簡単なものを作ったりしていましたが、echoを使ったプロジェクトに参画してから触れることなく過ごしてきました。 しかしGoでオススメのWebフレームワー ...

続きを見る

↑の記事で net/http パッケージを使ったHTTPサーバーの実装についてまとめましたが、今回はハンドラー関数をラップする方法をメモメモ。

アプリケーションを実装していると、ServeHTTP メソッドが呼ばれる前後に処理をはさみたいことがあります。

例えば、ログインが必要なハンドラーの場合は未ログインならログイン画面にリダイレクトさせるとか。

このようなときはハンドラー関数をラップすればOK。

サンプルコード

すべてmain.goに書く想定です。

例として、ログインしていなければログインページにリダイレクトさせるAuthHandlerを作ります。


package main

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

type AuthHandler struct {
	next http.Handler
}

func (h *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	token, err := r.Cookie("auth_token")
	if err == http.ErrNoCookie {
		// ログイン画面へリダイレクト
		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusTemporaryRedirect)
		return
	} else if err != nil {
		panic(err)
	}

	// 本来はcookieの値を検証して
	if len(token.Value) > 0 {
		// ラップされたハンドラを呼ぶ
		h.next.ServeHTTP(w, r)
	}
}

func MustAuth(handler http.Handler) http.Handler {
	return &AuthHandler{next: handler}
}

 

ログインしている必要がある場合は、この MustAuth を使えばOK。例えばマイページにアクセスするためにはログインしている必要があるとか。


type MyPageHandler struct{}

func (h *MyPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "マイページ")
}

func main() {
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "ログイン画面")
	})
	http.Handle("/mypage", MustAuth(&MyPageHandler{}))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

 

サンプルコード全体


package main

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

type AuthHandler struct {
	next http.Handler
}

func (h *AuthHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	token, err := r.Cookie("auth_token")
	if err == http.ErrNoCookie {
		// ログイン画面へリダイレクト
		w.Header().Set("Location", "/login")
		w.WriteHeader(http.StatusTemporaryRedirect)
		return
	} else if err != nil {
		panic(err)
	}

	// 本来はcookieの値を検証して
	if len(token.Value) > 0 {
		// ラップされたハンドラを呼ぶ
		h.next.ServeHTTP(w, r)
	}
}

func MustAuth(handler http.Handler) http.Handler {
	return &AuthHandler{next: handler}
}

type MyPageHandler struct{}

func (h *MyPageHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "マイページ")
}

func main() {
	http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "ログイン画面")
	})
	http.Handle("/mypage", MustAuth(&MyPageHandler{}))

	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

サンプルコード動作確認

go run main.go して

http://localhost:8080/mypage にアクセスします。 すると /login にリダイレクトされます。

次にdeveloper tools でcookieに適当な値を入れて

 

http://localhost:8080/mypage にアクセスすると「マイページ」と表示されます。

 

参考図書

Tour of Goを終えた人にオススメです!!

イチオシ記事

1

自己紹介 フリーランスエンジニアをしているヨノと申します。 独学でプログラミングを学び、ソシャゲ・SaaS開発などを経て、2018年からフリーランスエンジニアとして活動しています。 主にバックエンド中 ...

2

はじめまして、フリーランスエンジニアのヨノと申します。 自己紹介 独学でプログラミングを学び、ソシャゲ・SaaS開発などを経て、2018年からフリーランスエンジニアとして活動しています。 主にバックエ ...

3

ネット上で色々言われているフリーランスエンジニア....。「本当はどうなの?」と思っている人は多いでしょう。 そこで本記事ではフリーランスエンジニア5年生の私が、ネット上の意見も引用しながら実態を解説 ...

-Go言語