Cookie保存用户登录状态

cookie的工作流

Cookie可以通过服务器进行设置,相当于服务器给用户贴的一个标签,用于跟踪用户的状态

HTTP协议本身是无状态的,而应用服务器想保存一些状态,cookie应运而生,由服务器颁发,通过服务器设置的cookie信息通过响应头返回给浏览器,浏览器将响应头中的cookie信息保存在本地,当下次向服务器发送HTTP请求时,就自动将保存的这些cookie信息添加到HTTP请求头中,传递给服务器

这样的交互,服务器就可以在cookie里记录一些用户相关的信息,比如是否登录,账号等,然后根据这些信息做一些动作,比如接下来的示例中的保存登录状态的实现,就利用cookie。还有一些电子商务网站,实现购物车时也可能用到cookie

使用cookie保持登入态

在看cookie保存用户登录状态的效果前,我们先看下header中的cookies信息记录

header中的cookies

首次登入

响应头信息中增加Set-Cookie参数,但请求头信息中没有Cookie参数

image

第一次登入后已经将cookie存到了内存中

image

非首次登入

如果再次点击登录请求按钮,且在没有清空cookie的情况下,发送不同于前一个用户的登录信息,就会出现以下头部信息

image

此时本地的cookie信息也得到了更新

image

请求头中的Cookie字段是浏览器发送给服务器的cookie信息,cookie的值是之前存入内存中的userInfo("userName":"zhangsan")。响应头中的Set-Cookie字段是服务器返回给浏览器的cookie信息(实际上,随着用户登录信息的更新,cookie的值又被重新设置了)

因为没有使用删除已有cookie的直接方法,所以在使用相同的路径(path)、域(domain)和安全选项(secure)的情况下,会再次设置原cookie

上面的登入状态,是当我们登录成功后,在这个页面刷新,页面没有保存登录状态。接下来的效果是,后台cookie保存了用户登录状态,登录后刷新页面直接显示首页信息

使用cookie保持登入态

效果demo主要是通过express+nodejs实现的

处理POST正文数据

我们在demo中使用了HTML表单来接收用户名和密码,当我们提交表单信息时,浏览器会把表单内的数据按一定的格式组织之后编码进body,POST到指定的服务器地址

用户名和密码,在服务器端,可以通过HTML元素的名字属性的值找出来

服务器解析表单数据这一过程,是用express的body-parser中间件,只需要简单的配置即可:

var bodyParser = require("body-parser") // 加载body-parser模块
...
// 应用中间件
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())

express.Request对象req内有解析好的body,使用

app.post("/login",function(req,res,next){
    var userName = req.body.userName
    var password = req.body.password
    ...
}

就可以直接访问用户名和密码,也就是在HTML的input元素中的用户表单值,即建立关联

cookie

cookie存储的是一些key-value对。在express里,Request和Response都有cookie相关的方法。Request实例req的cookies属性,保存了解析出的cookie,如果浏览器没发送cookie,那这个cookies对象就是一个空对象

var Cookies=require('cookies')
app.use(function (req,res,next) {
    req.cookies=new Cookies(req,res)
    next();
})

实例化一个Cookies()方法,用来设置cookie,res.cookies.set('userInfo',JSON.stringify(...)),再通过res.cookies.get('userInfo')的方法来获取cookie

app.use(function (req,res,next) {
    req.cookies=new Cookies(req,res)
    console.log('cookies',typeof res.cookies.get('userInfo')) //返回 string
    //解析用户的cookie信息
    req.userInfo={};
    var cookiesUserInfo=res.cookies.get('userInfo')
    if(cookiesUserInfo){
        try{
            req.userInfo=JSON.parse(cookiesUserInfo)
        }catch(e){}
    }
    next()
})

第一次点击登录按钮post用户数据时,可以看到已经将用户基本信息写入响应头的set-Cookie了

app.post("/login",function(req,res,next){
    var userName = req.body.userName
    var password = req.body.password
    console.log("User name = "+ userName +",password is" + password)
    if(userName===''||password==='') {
        resoinseData.code = 1
        resoinseData.message = "用户名和密码不能为空!"
        res.json(resoinseData) // json格式返回给前端
        return
    }else {
        resoinseData.code = 200
        resoinseData.message = "登录成功!请再次刷新页面"
        resoinseData.userInfo = {
            _id:"5a40caa218013c1dd4eadcb0",
            userName:userName,
            password:password
        }
        req.cookies.set('userInfo',JSON.stringify(resoinseData.userInfo))
        res.json(resoinseData)
        return
    }
})

image

再次刷新页面时,请求头中已经出现了设置的cookie,用户进入免登入状态

app.get("/",function(req,res,next){
    if(req.userInfo.userName) {
        res.sendFile(path.resolve("index.html")) // 如果请求头中有cookie信息,则加载首页
    }else {
        res.sendFile(path.resolve("login.html")) // 如果请求头中没有cookie信息,则重新跳转登录页
    }  
})

image

再次点击退出按钮时,通过res.cookies.set('userInfo',null)会将先前设置的cookie信息删除,再次进入登入页

app.post("/loginout",function(req,res,next){
    req.cookies.set('userInfo',null)
    res.sendFile(path.resolve("login.html")) // 用户登出后再次跳转登录页
})

image

整个保持登入态的工作流:

用户登录 - 前端发送登录请求 - 后端保存用户cookie - 页面刷新 - 前端判断用户cookie存在 - 显示登录状态 - 用户退出 - 前端发送退出请求 - 后端清空用户cookie - 页面跳转登录页

完整的demo可以查看cookie-demo