摘要:通過瀏覽器的,可以看到此次會話的請求內容和響應內容。是協議的一部分。真實的產品,一般是創建一個保證唯一的,不易猜測出來的字符串。因此需要數據持久化的多提供者的方案。
使用過幾種Web App開發語言和框架,都會接觸到Session的概念。即使是一個簡單站點訪問計數的功能,也常常使用Session來實現的。其他常用的領域還有購物車,登錄用戶等。但是,對Session一直是一知半解,知其然而不知其所以然。
在認真的研究了HTTP協議,以及nodejs開發棧的express和express-session后,我終于比較有把握深入淺出的說清楚Session了,也算是滿足了多年來開發過程中,常常浮現的對Session的好奇心吧。
本文使用nodejs v9.5.0作為技術驗證工具。閱讀本文前需要了解基礎的HTTP知識和Cookie知識。詳細需要參考rfc6265,或者閱讀《HTTP小書》的最后一章。
會話的概念用戶在網站的一組相互關聯的的請求和響應,就是一次會話。簡而言之是這樣的:
會話 = 一組訪問
訪問 = 一次請求和響應
比如一個最簡單的nodejs HTTP程序:
var http = require("http") http.createServer(function(req,res){ res.end("hello") }).listen(3000)
每個請求都會進入到此處理函數:function(req,res){res.end("hello") },在此函數內獲得請求,處理響應,完成后發給客戶端,就是一次訪問。通過瀏覽器的developer tools,可以看到此次會話的請求內容和響應內容。
以站點計數應用為案例來說明的話,就是這些來自于同樣訪問者的多次訪問,都可以獲得當前站點的訪問計數。
引入會話我們從一個案例開始引入會話的概念。當我們需要訪問站點計數一類的功能時,我們希望用戶訪問此站點時:
第一次訪問時,顯示你的訪問次數為1
以后每次訪問時,訪問計數加1
此種情況下,我們需要有一個地方存儲當前計數,這樣才能在同一個客戶在此訪問時,可以取出當前計數,加一后返回給客戶。當然也因此需要識別此用戶(瀏覽器),為每個用戶多帶帶計數。就是說,不同的用戶訪問時,需要去取對應用戶的當前計數。
識別客戶的問題,常用的方法就是使用Cookie。Cookie是HTTP協議的一部分。HTTP可以通過頭字段Set-Cookie為來訪客戶做一個標記,這個標記常常就是一個ID,下一次訪問此站點時,HTTP會通過Cookie頭字段,發送此ID到站點,由此站點知道此客戶的身份和這個身份關聯的狀態信息,比如當前訪問計數,或者此身份當前的購物車的內容等等。
識別了客戶后,就可以在Web服務器內,為此客戶建立它的獨特的狀態信息。
實現一個會話基于nodejs HTTP模塊,我們實現一個極為簡單的Session服務。只是為了展示概念,而不是為了實用的目的。此服務可以實現一個共享于同一站點的多次訪問的req.session變量,此變量為一個對象,可以在此變量內寫入新的成員,或者修改現存的成員變量的值,每次訪問后會保存req.session,以便下次訪問可以得到當前的值:
var http = require("http") var sessionkey = "sessionkey3" http.createServer(function(req,res){ if (req.url =="/"){ session(req,res) req.session.count = (req.session.count+1) || 1 res.end("hi"+req.session.count) }else res.end("") }).listen(3000) console.log("listen on 3000") function session(req,res){ if (req.session) return var answer ,id if(isSessionOk(req)){ id = getCookie(req) answer = getSessionById(id) }else{ answer= {} id = createSession(answer) setCookie(res,id) } req.session = answer res.on("finish", function() { saveSession(id,req.session) }); } function hasCookie(req){ return (getCookie(req)!="") } function getCookie(req){ try{ var c = req.headers["cookie"] var arr = c.split(";") for (var i = 0; i < arr.length; i++) { var kv = arr[i] var a = kv.split("=") if (a[0].trim() == sessionkey) return a[1] } }catch(error){ return "" } return "" } function setCookie(res,id){ res.setHeader("set-cookie",sessionkey +"="+id) } var sessions = {} var sid = 0 function getSessionById(sid){ return sessions[sid] } function getSessionByReq(req){ var sid = getCookie(req) return sessions[sid] } function createSession(session){ sessions[sid++,session] return sid } function saveSession(sid,session){ sessions[sid] = session } function isSessionOk(req){ return hasCookie(req) && getSessionByReq(req) !== undefined }
程序代碼比較簡單,讀者可以保持它到index.js,然后執行此程序,驗證概念:
node index.js
然后,啟動chrome,訪問站點localhost:3000,然后多次刷新,你可以看到每次刷新,返回的訪問次數逐步累加。在打開另一個瀏覽器,比如safari,在此訪問此站點,你會發現返回的訪問計數從1開始,另外計數。因為是兩個不同的瀏覽器內器,這就保證的它們是不同的訪問客戶,在站點內的代碼,會區別兩者,分別記錄它們的狀態信息。
代碼使用了HTTP Cookie,基本算法很簡單:
如果Session沒有準備好,那么創建一個Session,得到Session的ID,把此ID通過Set-Cookie發送給瀏覽器。瀏覽器會在下一次訪問此站點時,發送此ID。
如果Session已經準備好了,也就是說,瀏覽器通過Cookie發來了ID,并且通過此ID,可以在站點內獲取到Session
把創建或者獲取的Session賦值給req對象
在請求處理函數生命周期內,可以獲取和修改Session對象
在請求處理完后,保存此Session變量
可能大家看到sessionkey這個變量,感覺有些莫名其妙。原因是每次cookie發送,同樣的站點可能有多個框架需要使用此cookie頭字段,比如php,aspx,jsp等都是需要使用了,為了好像不要沖突,大家各自使用cookie頭字段內各自的key/value對即可。比如php的key默認是phpsessid,express-session默認的是connect.sid。
總結此代碼演示了最基礎的Session的概念,但是遠遠不是一個可用的模塊,想要真實世界中使用的Session模塊,可以考慮express-session。
實現一個真正可以的會話,還需要考慮很多問題:
本文中使用是Session Id其實就是一個自增的整數。這會導致客戶端欺騙,黑客可以猜到SessionID,使用偽造的SessionID獲得服務器內對應的狀態數據,或者偽造登錄從而獲得更高權限。真實的產品,一般是創建一個保證唯一的,不易猜測出來的字符串。
本文中的Session每次end后會必然保存,而不管此Session是否修改。實際的產品,是需要考慮此優化的。同時,也需要考慮到Session的失效期,到了失效期就會銷毀,因為有些客戶可能來一次兩次也后再也不來訪問了,沒有必要為他們保存狀態信息,如果再來了,不妨重新創建會話即可。
本文的Session保存在內存中,一旦重啟,所有會話都會丟失。實際產品中,是需要支持持久化的保存的,比如保存到mysql數據庫內,redis內,mongodb內等等。因此需要數據持久化的多提供者的方案。
更多的考量,可以去通過閱讀express-session來獲得。本文閱讀完畢,本身就是可以成為閱讀express-session的基礎材料的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/94638.html
摘要:函數式編程,一看這個詞,簡直就是學院派的典范。所以這期周刊,我們就重點引入的函數式編程,淺入淺出,一窺函數式編程的思想,可能讓你對編程語言的理解更加融會貫通一些。但從根本上來說,函數式編程就是關于如使用通用的可復用函數進行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數式編程(Functional Programming),一...
摘要:咱媽說別亂點鏈接之淺談攻擊閱讀掘金作者馬達編輯迷鹿馬達,精通開發開發,擅長接口設計以及平臺化建設,獨自主導過多個產品。一題目購物應用分環境要求安全學習資料匯總掘金安全學習資料匯總安全學習網站收集 咱媽說別亂點鏈接之淺談 CSRF 攻擊 - 閱讀 - 掘金作者 | 馬達編輯 | 迷鹿 馬達, 精通PHP開發、Web開發,擅長api接口設計以及平臺化建設,獨自主導過多個Web產品。目前就職...
摘要:咱媽說別亂點鏈接之淺談攻擊閱讀掘金作者馬達編輯迷鹿馬達,精通開發開發,擅長接口設計以及平臺化建設,獨自主導過多個產品。一題目購物應用分環境要求安全學習資料匯總掘金安全學習資料匯總安全學習網站收集 咱媽說別亂點鏈接之淺談 CSRF 攻擊 - 閱讀 - 掘金作者 | 馬達編輯 | 迷鹿 馬達, 精通PHP開發、Web開發,擅長api接口設計以及平臺化建設,獨自主導過多個Web產品。目前就職...
閱讀 2092·2021-11-15 17:57
閱讀 762·2021-11-11 16:54
閱讀 2608·2021-09-27 13:58
閱讀 4113·2021-09-06 15:00
閱讀 966·2021-09-04 16:45
閱讀 3520·2019-08-30 15:56
閱讀 1797·2019-08-30 15:53
閱讀 1644·2019-08-30 14:12