Golang Session Note 1

Rain Wu
Golang 筆記
Published in
6 min readApr 23, 2019

又是一個在咖啡廳伴著拿鐵,創造力蠢蠢欲動的早晨~
又是篇一個早上寫不完,拖到隔天晚上才寫完的文章 Orz

上一篇文章 Golang Session Note 0 雖然頂著 Session 筆記的名號,但怎麼內盡是些編碼解碼、時效設定的東西呢? Well~ 因為就是那些功能支撐起了接下來要實作的 Session 機制,我手癢看了下原始碼就順便寫筆記了,那麼這篇文章就來實作應用於 router 中各個 Handle Function 吧

Router

先附上 Router 的布局

預計是在 index 實現首頁,會依照 Session 狀態決定是否呈現登入介面,login 來處理登入邏輯,成功的話進到 secret,失敗的話便導向 forbidden,整個服務會監聽 8080 port。

index

沒意外的話,我們是被得先找到究竟是哪一個 Session 是匹配的才能繼續做事對吧?line 2 的 store.Get 幫我們做了這件事,來看看他具體怎做的:

看起來是個夾在中間做處理的,最主要還是用於註冊 Session 的 GetRegistry 方法:

先從 Client 發來的 request 中取得 Context 裡的資訊,如果是 nil 的話便會回傳預設的 context.Background,若不為 nil 則能取得一個實現了 Context 介面的結構體,其中的 Value 方法部分註解敘述如下:

很明顯的他是規定了一個透過 key 取 value 的方法,GetRegistry 的 line 6 進行 type assertion 把透過 registryKey 取回的 registry 變數成了 Registry 結構體的指針。若取到 nil 也無妨,line 8 ~ 11 新建了一個 Registry ,能透過 Context 特定的方法寫入資訊並回傳 (e.g. WithContext、WithValue)。

Context 內部具體如何運行的和本文比較沒有關連,我最近也還沒時間弄清楚,所以就先不寫了。他是 1.7 版才有的新 package,根據各路大神的說法這機制限制頗不嚴謹,導致用法花樣百出,究竟哪一種才是標準也是爭論不休,詳細究參考 這篇 文章吧~

現在我們確定 GetRegistry 能為我們帶回來一個 Registry 結構的指針了,來看看內部有哪些元件:

一個 http.Request 指針還有他執行期間用到的 Session 資訊......? 那究竟是什麼樣的資訊阿?

放的就是一些意料之內的東西,一個 Session 結構和錯誤資料,Session 結構裡面有作為檔案名用的隨機亂碼 ID、什麼都吃看起來就很容易濫用失控的 Values、設定用的 Options,當初在 resgister 時儲存自己的 store 結構等等。現在我們知道裡面都是些什麼東西了,可以觀察一下 Get 函數做了什麼事了

由 Comments 可知主要是個透過給定名稱在目前儲存庫裡面找出對應 session 的方法,line 5~7 有做了 isCookieNameValid 檢測有沒有奇怪的 CookieName,屬於比較 lexical 的東西:

line 5 打算用 IndexFunc 來判斷是否有不合法的 Token,若沒有的話,IndexFunc 會回傳 -1,而使得 isCookieNameValid 回傳 true。

Get 函數的 line 8~10 嘗試以 name 作為 key 找 session,找到的話就把資訊存下來,沒找到的話 line 10~14 直接新生成一個出來並放到 Registry 裡面,最後 line 15 順便換上了儲存自己的 store 結構,現在來看看 store.New 是怎麼註冊新 Sessions 的,這次是用 FilesystemStore 實作的,所以也要找到對應的 New 函數

line 5 產出一個新的 Session 後面就都是附值、 error handle、解碼的部分了,可以發現這部分並沒有取得 Registry 參數因此無法放進 Registry 裡面,但基於一個 FilesystemStore 結構衍生的方法卻也沒直接附上儲存的 store,這我就看不太懂了 @A@ ,不過能發現 IsNew 值的更動和放入 Registry 都因此提前到附上 store 之前執行,猜測也許是在這兩個部分受到限制,還望各位路過的大大指點了~

好的~ 現在總算安排好我們取到一個和指定的 name key 匹配 session 的流程了,index 的 line 3~6 是在做 error handling,如果仍是在取 session 時出了什麼差錯,就丟一個 StatusInternalServerError 出來,狀態碼是 500,白話文是「Server 遇到了她處理不來的問題,所以沒辦法響應你的 Request」

接下來看看取得 Session 中 User data 的部分,也就是 line 7 的部分,原教學文把他包成另一個函數:

line 4 從 Session 中的 Values 透過 user 這個 key 取出 data,並在 line 6 用 type assertion 後賦值給 line 5 宣告的空 user 結構,就是一個 mapping 資料進去的概念。如果出問題的話就代表 User data 有些疑慮,所以把 Authenticated 的認證狀態否定掉要求重新登入,沒問題的話就維持不變直接回傳。

回傳之後再 index 的 line 8 由 tpl 執行 index.gohtml 模板,帶入 user 參數,並透過 http.ResponseWriter 響應回復 Client 端的請求:

看 Gist 的 render 結果應該是還沒支持 gohtml 的語法高亮,但 vscode 有支持的插件!(偉哉 vscode!)這檔名一定要是 gohtml,不是 html,go 會以 data-driven 的機制依照參數生成相對應的 html,如果你網頁全白的話注意一下是不是寫成 html 檔了~

主要差異在 line 12~21,分別依照 line 12 和 line 15 不同條件生成不同的內容,因此傳入的 user data 中的 Authenticated 會因此造成相異的結果,以此方式來做為 session 維持與否的 Client 端呈現。

最近買了本新書,雖然書單已經排了一大堆了但我還是覺得該買,同時因為很多大大都極力推薦,所以我決定跳過原本預計要讀的,先讀這本新書。這次就寫到這裡,如果有大大路過的話跪求指點一下 QwQ

--

--

Rain Wu
Golang 筆記

A software engineer specializing in distributed systems and cloud services, desire to realize various imaginations of future life through technology.