成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Web Session 淺入淺出

李昌杰 / 1285人閱讀

摘要:通過(guò)瀏覽器的,可以看到此次會(huì)話的請(qǐng)求內(nèi)容和響應(yīng)內(nèi)容。是協(xié)議的一部分。真實(shí)的產(chǎn)品,一般是創(chuàng)建一個(gè)保證唯一的,不易猜測(cè)出來(lái)的字符串。因此需要數(shù)據(jù)持久化的多提供者的方案。

使用過(guò)幾種Web App開(kāi)發(fā)語(yǔ)言和框架,都會(huì)接觸到Session的概念。即使是一個(gè)簡(jiǎn)單站點(diǎn)訪問(wèn)計(jì)數(shù)的功能,也常常使用Session來(lái)實(shí)現(xiàn)的。其他常用的領(lǐng)域還有購(gòu)物車(chē),登錄用戶等。但是,對(duì)Session一直是一知半解,知其然而不知其所以然。

在認(rèn)真的研究了HTTP協(xié)議,以及nodejs開(kāi)發(fā)棧的express和express-session后,我終于比較有把握深入淺出的說(shuō)清楚Session了,也算是滿足了多年來(lái)開(kāi)發(fā)過(guò)程中,常常浮現(xiàn)的對(duì)Session的好奇心吧。

本文使用nodejs v9.5.0作為技術(shù)驗(yàn)證工具。閱讀本文前需要了解基礎(chǔ)的HTTP知識(shí)和Cookie知識(shí)。詳細(xì)需要參考rfc6265,或者閱讀《HTTP小書(shū)》的最后一章。

會(huì)話的概念

用戶在網(wǎng)站的一組相互關(guān)聯(lián)的的請(qǐng)求和響應(yīng),就是一次會(huì)話。簡(jiǎn)而言之是這樣的:

會(huì)話 = 一組訪問(wèn)

訪問(wèn) = 一次請(qǐng)求和響應(yīng)

比如一個(gè)最簡(jiǎn)單的nodejs HTTP程序:

var http = require("http")
http.createServer(function(req,res){
    res.end("hello")    
}).listen(3000)

每個(gè)請(qǐng)求都會(huì)進(jìn)入到此處理函數(shù):function(req,res){res.end("hello") },在此函數(shù)內(nèi)獲得請(qǐng)求,處理響應(yīng),完成后發(fā)給客戶端,就是一次訪問(wèn)。通過(guò)瀏覽器的developer tools,可以看到此次會(huì)話的請(qǐng)求內(nèi)容和響應(yīng)內(nèi)容。

以站點(diǎn)計(jì)數(shù)應(yīng)用為案例來(lái)說(shuō)明的話,就是這些來(lái)自于同樣訪問(wèn)者的多次訪問(wèn),都可以獲得當(dāng)前站點(diǎn)的訪問(wèn)計(jì)數(shù)。

引入會(huì)話

我們從一個(gè)案例開(kāi)始引入會(huì)話的概念。當(dāng)我們需要訪問(wèn)站點(diǎn)計(jì)數(shù)一類的功能時(shí),我們希望用戶訪問(wèn)此站點(diǎn)時(shí):

第一次訪問(wèn)時(shí),顯示你的訪問(wèn)次數(shù)為1

以后每次訪問(wèn)時(shí),訪問(wèn)計(jì)數(shù)加1

此種情況下,我們需要有一個(gè)地方存儲(chǔ)當(dāng)前計(jì)數(shù),這樣才能在同一個(gè)客戶在此訪問(wèn)時(shí),可以取出當(dāng)前計(jì)數(shù),加一后返回給客戶。當(dāng)然也因此需要識(shí)別此用戶(瀏覽器),為每個(gè)用戶多帶帶計(jì)數(shù)。就是說(shuō),不同的用戶訪問(wèn)時(shí),需要去取對(duì)應(yīng)用戶的當(dāng)前計(jì)數(shù)。

識(shí)別客戶的問(wèn)題,常用的方法就是使用Cookie。Cookie是HTTP協(xié)議的一部分。HTTP可以通過(guò)頭字段Set-Cookie為來(lái)訪客戶做一個(gè)標(biāo)記,這個(gè)標(biāo)記常常就是一個(gè)ID,下一次訪問(wèn)此站點(diǎn)時(shí),HTTP會(huì)通過(guò)Cookie頭字段,發(fā)送此ID到站點(diǎn),由此站點(diǎn)知道此客戶的身份和這個(gè)身份關(guān)聯(lián)的狀態(tài)信息,比如當(dāng)前訪問(wèn)計(jì)數(shù),或者此身份當(dāng)前的購(gòu)物車(chē)的內(nèi)容等等。

識(shí)別了客戶后,就可以在Web服務(wù)器內(nèi),為此客戶建立它的獨(dú)特的狀態(tài)信息。

實(shí)現(xiàn)一個(gè)會(huì)話

基于nodejs HTTP模塊,我們實(shí)現(xiàn)一個(gè)極為簡(jiǎn)單的Session服務(wù)。只是為了展示概念,而不是為了實(shí)用的目的。此服務(wù)可以實(shí)現(xiàn)一個(gè)共享于同一站點(diǎn)的多次訪問(wèn)的req.session變量,此變量為一個(gè)對(duì)象,可以在此變量?jī)?nèi)寫(xiě)入新的成員,或者修改現(xiàn)存的成員變量的值,每次訪問(wèn)后會(huì)保存req.session,以便下次訪問(wèn)可以得到當(dāng)前的值:

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
}

程序代碼比較簡(jiǎn)單,讀者可以保持它到index.js,然后執(zhí)行此程序,驗(yàn)證概念:

node index.js 

然后,啟動(dòng)chrome,訪問(wèn)站點(diǎn)localhost:3000,然后多次刷新,你可以看到每次刷新,返回的訪問(wèn)次數(shù)逐步累加。在打開(kāi)另一個(gè)瀏覽器,比如safari,在此訪問(wèn)此站點(diǎn),你會(huì)發(fā)現(xiàn)返回的訪問(wèn)計(jì)數(shù)從1開(kāi)始,另外計(jì)數(shù)。因?yàn)槭莾蓚€(gè)不同的瀏覽器內(nèi)器,這就保證的它們是不同的訪問(wèn)客戶,在站點(diǎn)內(nèi)的代碼,會(huì)區(qū)別兩者,分別記錄它們的狀態(tài)信息。

代碼使用了HTTP Cookie,基本算法很簡(jiǎn)單:

如果Session沒(méi)有準(zhǔn)備好,那么創(chuàng)建一個(gè)Session,得到Session的ID,把此ID通過(guò)Set-Cookie發(fā)送給瀏覽器。瀏覽器會(huì)在下一次訪問(wèn)此站點(diǎn)時(shí),發(fā)送此ID。

如果Session已經(jīng)準(zhǔn)備好了,也就是說(shuō),瀏覽器通過(guò)Cookie發(fā)來(lái)了ID,并且通過(guò)此ID,可以在站點(diǎn)內(nèi)獲取到Session

把創(chuàng)建或者獲取的Session賦值給req對(duì)象

在請(qǐng)求處理函數(shù)生命周期內(nèi),可以獲取和修改Session對(duì)象

在請(qǐng)求處理完后,保存此Session變量

可能大家看到sessionkey這個(gè)變量,感覺(jué)有些莫名其妙。原因是每次cookie發(fā)送,同樣的站點(diǎn)可能有多個(gè)框架需要使用此cookie頭字段,比如php,aspx,jsp等都是需要使用了,為了好像不要沖突,大家各自使用cookie頭字段內(nèi)各自的key/value對(duì)即可。比如php的key默認(rèn)是phpsessid,express-session默認(rèn)的是connect.sid。

總結(jié)

此代碼演示了最基礎(chǔ)的Session的概念,但是遠(yuǎn)遠(yuǎn)不是一個(gè)可用的模塊,想要真實(shí)世界中使用的Session模塊,可以考慮express-session。

實(shí)現(xiàn)一個(gè)真正可以的會(huì)話,還需要考慮很多問(wèn)題:

本文中使用是Session Id其實(shí)就是一個(gè)自增的整數(shù)。這會(huì)導(dǎo)致客戶端欺騙,黑客可以猜到SessionID,使用偽造的SessionID獲得服務(wù)器內(nèi)對(duì)應(yīng)的狀態(tài)數(shù)據(jù),或者偽造登錄從而獲得更高權(quán)限。真實(shí)的產(chǎn)品,一般是創(chuàng)建一個(gè)保證唯一的,不易猜測(cè)出來(lái)的字符串。

本文中的Session每次end后會(huì)必然保存,而不管此Session是否修改。實(shí)際的產(chǎn)品,是需要考慮此優(yōu)化的。同時(shí),也需要考慮到Session的失效期,到了失效期就會(huì)銷毀,因?yàn)橛行┛蛻艨赡軄?lái)一次兩次也后再也不來(lái)訪問(wèn)了,沒(méi)有必要為他們保存狀態(tài)信息,如果再來(lái)了,不妨重新創(chuàng)建會(huì)話即可。

本文的Session保存在內(nèi)存中,一旦重啟,所有會(huì)話都會(huì)丟失。實(shí)際產(chǎn)品中,是需要支持持久化的保存的,比如保存到mysql數(shù)據(jù)庫(kù)內(nèi),redis內(nèi),mongodb內(nèi)等等。因此需要數(shù)據(jù)持久化的多提供者的方案。

更多的考量,可以去通過(guò)閱讀express-session來(lái)獲得。本文閱讀完畢,本身就是可以成為閱讀express-session的基礎(chǔ)材料的。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94638.html

相關(guān)文章

  • SegmentFault 技術(shù)周刊 Vol.16 - 淺入淺出 JavaScript 函數(shù)式編程

    摘要:函數(shù)式編程,一看這個(gè)詞,簡(jiǎn)直就是學(xué)院派的典范。所以這期周刊,我們就重點(diǎn)引入的函數(shù)式編程,淺入淺出,一窺函數(shù)式編程的思想,可能讓你對(duì)編程語(yǔ)言的理解更加融會(huì)貫通一些。但從根本上來(lái)說(shuō),函數(shù)式編程就是關(guān)于如使用通用的可復(fù)用函數(shù)進(jìn)行組合編程。 showImg(https://segmentfault.com/img/bVGQuc); 函數(shù)式編程(Functional Programming),一...

    csRyan 評(píng)論0 收藏0
  • 信安 - 收藏集 - 掘金

    摘要:咱媽說(shuō)別亂點(diǎn)鏈接之淺談攻擊閱讀掘金作者馬達(dá)編輯迷鹿馬達(dá),精通開(kāi)發(fā)開(kāi)發(fā),擅長(zhǎng)接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)產(chǎn)品。一題目購(gòu)物應(yīng)用分環(huán)境要求安全學(xué)習(xí)資料匯總掘金安全學(xué)習(xí)資料匯總安全學(xué)習(xí)網(wǎng)站收集 咱媽說(shuō)別亂點(diǎn)鏈接之淺談 CSRF 攻擊 - 閱讀 - 掘金作者 | 馬達(dá)編輯 | 迷鹿 馬達(dá), 精通PHP開(kāi)發(fā)、Web開(kāi)發(fā),擅長(zhǎng)api接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)Web產(chǎn)品。目前就職...

    lushan 評(píng)論0 收藏0
  • 安全攻防戰(zhàn) - 收藏集 - 掘金

    摘要:咱媽說(shuō)別亂點(diǎn)鏈接之淺談攻擊閱讀掘金作者馬達(dá)編輯迷鹿馬達(dá),精通開(kāi)發(fā)開(kāi)發(fā),擅長(zhǎng)接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)產(chǎn)品。一題目購(gòu)物應(yīng)用分環(huán)境要求安全學(xué)習(xí)資料匯總掘金安全學(xué)習(xí)資料匯總安全學(xué)習(xí)網(wǎng)站收集 咱媽說(shuō)別亂點(diǎn)鏈接之淺談 CSRF 攻擊 - 閱讀 - 掘金作者 | 馬達(dá)編輯 | 迷鹿 馬達(dá), 精通PHP開(kāi)發(fā)、Web開(kāi)發(fā),擅長(zhǎng)api接口設(shè)計(jì)以及平臺(tái)化建設(shè),獨(dú)自主導(dǎo)過(guò)多個(gè)Web產(chǎn)品。目前就職...

    chanthuang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<