# session、cookie
# 什么是 cookie
- 存储在浏览器的一段字符串(最大5kb)
- 跨域不共享
- 格式k1=v1;k2=v2;因此可以存储结构化数据
- 每次发送 http 请求,会将请求域的 cookie 一起发送给 server
- server 可以修改 cookie 并返回给浏览器
- 浏览器也可以通过 JavaScript 修改 cookie(有限制)
客户端修改 cookie:
document.cookie = 'k1 = 100'
// 只会是追加到原本的 cookie 的后面
server 端 nodejs 操作 cookie
// 获取
const cookiestr = req.headers.cookie
// 修改 cookie
res.setHeader('Set-Cookie', `username=${username}; path=/; httpOnly`)
一般设置 cookie 是用户在登录的时候,如果登录验证成功,就通过 setHeader 方法进行设置 cookie;也会设置 cookie 的 expires 过期时间。
# session
如果单纯使用 cookie,进行验证登录,会暴露一些用户信息,比如用户名或者邮箱等等。 对于登录,我们可以在 cookie 中存储 userID,server 端对应 username。 存储会话信息。session,也就是 server 端存储用户信息。
# 结合 session 以及 cookie 实现登录
结合 session 以及 cookie,我们在做登录的时候,首先在进入处理后台,首先判断客户端是否携带 cookie:
// 解析 cookie
req.cookie = {}
const cookieStr = req.headers.cookie || ''
cookieStr.split(';').forEach(item => {
if(!item) {
return
}
const arr = item.split('=')
const key = arr[0].trim()
const val = arr[1].trim()
req.cookie[key] = val
})
然后根据前面的判断从 cookie 中获取 userId:如果没有 userId ,就生成 userId,为当前时间戳加随机数,如果从 cookie 中能解析到 userId ,设置 sessionId 为 userId,然后从 redis 中根据 userId 读取 session,如果没有 session 信息,就设置 req.sessionId 为空对象,表示没有用户登录,以及设置 session 为空对象。如果能读取到用户的 session 信息,就将请求体的 session 字段设置为用户的 session 信息;
// 解析session
let needSetCookie = false
let userId = req.cookie.userid
if(!userId) {
userId = `${Date.now()}_${Math.random()}`
needSetCookie = true
}
req.sessionId = userId
get(req.sessionId).then(val => {
if(val === null) {
set(req.sessionId, {})
// 设置session
req.session = {}
} else {
req.session = val
}
})
如果没有 cookie 就进行设置 cookie;然后在处理路由的时候,需要验证是否有 session 信息,如果没有就提示尚未登录:
// 处理 post data
getPostData(req).then(postData => {
req.body = postData
// handleBlogRouter 这里处理路由信息-其中包含下面 ,处理路由验证是否有 session 信息,如果没有返回 Promise 对象;
const blogReault = handleBlogRouter(req, res)
if(blogReault) {
blogReault.then(blogData => {
if(needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(blogData)
)
})
return
}
res.writeHead(404, {'Content-type': 'text/plain'})
res.write('404 Not Found\n')
res.end()
})
}
处理路由验证是否有 session 信息:
// 统一的登录验证函数
const loginCheck = (req) => {
if(!req.session.username) {
return Promise.resolve(
new ErrorModel('尚未登录')
)
}
}
if(method === 'POST' && req.path === '/api/blog/new') {
// 检测是否登录
const loginCheckResult = loginCheck(req)
if(loginCheckResult) {
// 未登录
return loginCheckResult
}
req.body.author = req.session.username
const result = newBlog(req.body)
return result.then(data => {
return new SuccessModel(data)
})
}
阅读量: