GoにおけるCookie操作(設定・送信・取得)について気になったので、本やネットで調べて自分なりにまとめてみました。
Cookieおさらい
正式には「HTTP cookie」でWebサイトへアクセスした際に、ユーザのデバイス(PCやスマホ)に残していくデータのことです。
サーバからHTTPレスポンスメッセージを通して送られるもので、クライアントに保管されます。次回以降はCookieとともにWebサーバーへアクセスするため、ユーザが保持していたCookieにあわせてページを表示することができます。
分類としてはセッションクッキーと永続性クッキーの2種類に分けられます。
Goにおけるtype Cookie
httpパッケージのtype Cookieは以下のような構造体になっています。
基本的にはhttp.Cookie型へのポインタ変数を用意し、NameフィールドにCookie名、ValueフィールドにCookieの値を入れて設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds MaxAge int Secure bool HttpOnly bool SameSite SameSite // Go 1.11 Raw string Unparsed []string // Raw text of unparsed attribute-value pairs } |
ExpiresとMaxAgeフィールドをしているすることで有効期限を設定することができます。
Expiresフィールドは、Cookieの期限切れとなるtime.Time型を指定します。
1 | ex) Expires: time.Now().Add(24 * time.Hour) // 24時間後に期限切れ |
MaxAgeフィールドは、ブラウザ内で生成されてからどれだけの期間有効かを指定します。ちなみに秒単位です。
1 | ex) MaxAge: 60 * 60 // 1時間後に期限切れ |
Expiresはほぼ全てのブラウザに対応しているが、HTTP1.1以降では非推奨となり、MaxAgeが推奨されています。ただ、MaxAgeはIE6、7、8で対応されていません。
参考:https://golang.org/pkg/net/http/#Cookie
Cookieの設定・送信
http.Cookie型へのポインタ変数を用意し、それぞれのフィールドに値を入れ、http.ResponseWriterとcookieを引数にセットします。
1 2 3 4 5 6 | cookie := &http.Cookie{ Name: "sample_name", Value: "sample_value", HttpOnly: true, } http.SetCookie(writer, cookie) |
実際に使われる例として、ユーザログイン時にCookieを生成する場合だと以下のような流れになります。
メールアドレスとパスワードがPOSTされ、メールアドレスからユーザが存在するかをチェックします。ここでのdata.UserByEmailメソッド(処理は省略)はメールアドレスからユーザを取得してきています。
次にPOSTされたパスワードが取得したユーザのパスワードと一致しているかをチェックし、user.CreateSession()メソッド(処理は省略)でサーバ側で持つセッションを生成してセッションテーブルにインサートします。
その後、Cookieをセットしログイン後のページにリダイレクトさせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | func auth(writer http.ResponseWriter, request *http.Request) { err := request.ParseForm() user, err := data.UserByEmail(request.PostFormValue("email")) if err != nil { danger(err, "ユーザが見つかりませんでした。") } if user.Password == data.Encrypt(request.PostFormValue("password")) { session, err := user.CreateSession() if err != nil { danger(err, "セッションを生成することができません。") } cookie := &http.Cookie{ Name: "auth", Value: session.Uuid, HttpOnly: true, } http.SetCookie(writer, cookie) http.Redirect(writer, request, "/", 302) } else { http.Redirect(writer, request, "/login", 302) } } |
Cookieの取得
構造体RequestのCookieメソッドを使用して、HTTPリクエストからのCookieを取得できます。指定したCookieが存在しない場合はエラーを返します。
複数のCookieを取得したい場合は、Cookiesを使うことで全てのCookieをスライスに入れて取得できます。
cookie.ValueでCookieの値を取得することができます。
1 2 3 4 5 | cookie, err := request.Cookie("sample") if err == nil { v := cookie.Value } |
実際に使われる例として、クライアントとサーバ間でのCookieのやりとりの場合、以下のような流れになります。
request.Cookie()メソッド(処理は省略)でCookieを取得し、Session構造体にセットします。
その後、送られてきたセッションをチェックし、無効の場合はエラーにします。
1 2 3 4 5 6 7 8 9 10 | func session(writer http.ResponseWriter, request *http.Request) (sess data.Session, err error) { cookie, err := request.Cookie("auth") if err == nil { sess = data.Session{Uuid: cookie.Value} if ok, _ := sess.Check(); !ok { err = errors.New("セッションが無効です") } } return } |
GoにおけるCookie操作についてのまとめでした。