今後のことを考え、PHPでの開発はSOY Shopを動かす時ぐらいにして、
主力はGolangに移していきたいなとコードを書いていたところ、
Golangで立てたWebサーバでのセッションの取り扱いで苦戦した。
セッションとかはさすがPHP!
Webアプリ専用の言語だけあってよくできてる。
前置きはここまでにしておいて、
今回Golangで苦戦した箇所をメモとして残しておく
Golangの現在のバージョン(1.5.2)では、
標準でセッションを扱うためのライブラリはない。
そこで、
Gorilla web toolkitのsessionsパッケージを利用することにした。
はじめにGolang標準のテンプレートエンジンを利用する為に、
下記の様にPageの構造体を用意
type Page struct { Name string Email string }
これを作っておくことで、いろいろと便利なことがあるんだけど置いといて
とあるページでフォームを表示出来るようにハンドラ用の関数を用意
import ( "html" "html/template" "net/http" "github.com/gorilla/sessions" ) func Page1(w http.ResponseWriter, r *http.Request) { page := Page{} t, _ := template.ParseFiles("register.html") t.Execute(w, page) }
register.htmlにはフォームのHTMLを記述して、
実行してみると
こんな感じ。
confirmを押すと、確認画面を表示して、
表示する直前にセッションに入力した値を入れる仕様にしておく。
確認ページの関数は下記の通り
var store = sessions.NewCookieStore([]byte("random-string")) func Page2(w http.ResponseWriter, r *http.Request) { r.ParseForm() //戻るボタンを押した if backBtn := r.FormValue("back"); len(backBtn) > 0 { //トップページへ戻る http.Redirect(w, r, "/", http.StatusFound) return } else { name := html.EscapeString(r.FormValue("name")) email := html.EscapeString(r.FormValue("email")) //セッションに値を入れる処理 session, _ := store.Get(r, "goapp-p-register") session.Values["name"] = name session.Values["email"] = email session.Save(r, w) //ここからページの表示に関する処理 page := Page{Name:name, Email:email} t, err := template.ParseFiles("confirm.html") if err != nil { panic(err) } err = t.Execute(w, page) // テンプレートをジェネレート if err != nil { panic(err) } } }
Page2からbackボタンでPage1に戻った時に、
入力しておいた値をフォームに入れておきたいわけで、
func Page1(w http.ResponseWriter, r *http.Request) { session, _ := store.Get(r, "goapp-p-register") name := session.Values["name"] email := session.Values["email"] page := Page{Name: name, Email: email} t, _ := template.ParseFiles("register.html") t.Execute(w, page) }
上記の様にページを表示する前にセッションに入れた値を取得して、フォームに値を入れる様に書き換えた後、このコードを実行してみたところ
page := Page{Name: name, Email: email}
の箇所で、
main.go:28: cannot use name (type interface {}) as type string in field value: need type assertion
というエラーが表示された。
?
nameの型がinterface{}だって?
とりあえず、
name := session.Values["name"] log.Printf("#v", name)
のようにしてセッションの中から取り出した値を見てみると、
#v%!(EXTRA string=齋藤 毅)
name変数の型はstringになってるぞ。
エラーメッセージはstringにアサーションをしてみろとのことだったので、
name := session.Values["name"] if _, ok := name.(string); !ok{ log.Printf("#v", ok) }
をしてみたら、
#v%!(EXTRA bool=true)
が返ってきたのに、アサーションしたものを構造体に入れてもダメだった。
どうすれば良いのか?といろいろと考えてみた結果、
type Page struct { Name interface{} Email interface{} }
にしてみたら、うまくいった。
構造体に値を突っ込むとき、
構造体の方では静的な型を見るけど、
name := session.Values["name"]
では、動的に型を定義するみたいで、
構造体に突っ込むときに動的に定義した型の値ではダメみたいだ。
何か良い方法はないかな?