《深入浅出 node.js 笔记》 - part3

相关链接
文章目录
第 8 章 构建 Web 应用
的处理分为如下几步:
是被放在请求头中的而不是请求体中,原生 Node 可以通过 req.. 来获取到 。
我们来看下设置的 Set- 字段:
Set-Cookie: name=value; Path=/; Expires=Sun, 23-Apr-23 09:01:35 GMT; Domain=.domain.com;
其中 name = value 是必须包含的部分,其余部分皆是可选参数 。
// 封装方法快速设置 Cookie/*** * @param {*} name 该 Cookie 的键* @param {*} val该 Cookie 的值* @param {*} opt可选参数*/const serialize = function (name, val, opt) {const pairs = [`${name}=${val}`]opt = opt || {}if (opt.maxAge) pairs.push(`Max-Age=${opt.maxAge}`)if (opt.domain) pairs.push(`Domain=${opt.domain}`)if (opt.path) pairs.push(`Path=${opt.path}`)if (opt.expires) pairs.push(`Expires=${opt.expires}`)if (opt.httpOnly) pairs.push(`HttpOnly`)if (opt.secure) pairs.push(`Secure`)return pairs.join('; ')}const handler = function (req, res) {if (!req.cookies.isVisit) {res.setHeader('Set-Cookie', serialize('isVisit', 1))res.writeHead(200)res.end('欢迎第一次到来')} else {res.writeHead(200)res.end('再次欢迎你')}}// res.setHeader 的第二个参数可以是一个数组res.setHeader('Set-Cookie', [serialize('foo', 'bar'), serialize('baz', 'val')])// 这会在报文头部形成两条 Set-Cookie 字段// Set-Cookie: foo=bar; Path=/; Expires= ...; Domain=.domain.com// Set-Cookie: baz=val; Path=/; Expires= ...; Domain=.domain.com
的性能影响:
一旦设置过多,将会导致报头较大,大多数的并不需要每次都用上 。
如果在域名的根节点设置 (Path = /),几乎所有子路径下的请求都会带上这些 ,而它们在有些情况下是无用的,比如静态文件 。
最严重的的问题就是前后端都可以进行修改, 的数据只保留在服务器端,客户端无法修改,但是仍然需要使用实现用户和数据的映射,一旦服务器端启用了 ,它将约定一个键值作为的口令 。
一旦服务器检查到用户请求中没有携带该值,它就会为之生成一个值,这个值是唯一且不重复的值,并设定超时时间 。
PS:以下代码为原生 node.js 实现的,现在一般使用 - 插件配置一下就可以实现相同的功能(我用的时候有 bug 搞不定),所以有时候还是了解下原生实现的好 。另外,这里的是存在内存中的,现在一般存在 redis 。
const sessions = {}const key = 'session_id'const EXPIRES = 20 * 60 * 1000const generate = function () {const session = {}session.id = (new Date()).getTime() + Math.random()session.cookie = {expires: (new Date()).getTime() + EXPIRES}sessions[session.id] = sessionreturn session}function (req, res) {const id = req.cookies[key]if (!id) {req.session = generate()} else {const session = sessions[id]if (session) {if (session.cookie.expire > (new Date()).getTime()) {// 更新超时时间session.cookie.expire = (new Date()).getTime() + EXPIRESreq.session = session} else {// 超时了,删除旧的数据,并重新生成delete session[id]req.session = generate()}} else {// 如果 sesion 过期或口令不对,重新生成 sessionreq.session = generate()}}handler(req, res)}// 我们还需要再响应时添加相应头部// hack 响应对象的 writeHead() 方法let writeHead = res.writeHeadres.writeHead = function () {const cookies = res.getHeader('Set-Cookie')const session = serialize('Set-Cookie', req.session.id)cookies = Array.isArray(cookies) ? cookies.concat(session) : [cookies, session]res.setHeader('Set-Cookie', cookies)return writeHead.apply(this, arguments)}// 业务逻辑const handler = function (req, res) {if (!req.session.isVisit) {res.session.isVisit = trueres.writeHead(200)res.end('欢迎第一次来到动物园')} else {res.writeHead(200)res.end('动物园再次欢迎你')}}