nodejs mysql session_NodeJS 使用 cookie 和 session

22657a43a04b027841a5f30d3b7241de.png

前言

由于浏览器无状态的特性,cookie 技术应运而生,cookie 是一个会话级的存储,大小 4KB 左右,用于浏览器将服务器设置的信息重新带给服务器进行验证,不支持跨域,在浏览器清空缓存或超过有效期后失效,不能存放敏感信息,session 是专门用于存储最初设置给浏览器 cookie 数据的地方,我们本篇就来讨论一下 cookie 和 session 在 NodeJS 中的使用方式。

cookie 的基本使用

1、NodeJS 原生操作 cookie

下面是 cookie 在 Node 原生中的读取和写入方法。

// 原生中操作 cookie

const http = require("http");

// 创建服务

http.createServer((req, res) => {

if (req.url === "/read") {

// 读取 cookie

console.log(req.headers.cookie);

res.end(req.headers.cookie);

} else if (req.url === "/write") {

// 设置 cookie

res.setHeader("Set-Cookie", [

"name=panda; domain=panda.com; path=/write; httpOnly=true",

`age=28; Expires=${new Date(Date.now() + 1000 * 10).toGMTString()}`,

`address=${encodeURIComponent("回龙观")}; max-age=10`

]);

res.end("Write ok");

} else {

res.end("Not Found");

}

}).listen(3000);

上面代码创建了一个 http 服务器,可以通过读取 cookie 请求头的值来获取浏览器发来的 cookie,服务器可以通过给浏览器设置响应头 Set-Cookie 实现对浏览器 cookie 的设置,多个 cookie 参数为数组,在数组内可以规定每一条 cookie 的规则,中间使用一个分号和一个空格隔开。

domain 用来设置允许访问 cookie 的域;

path 用来设置允许访问 cookie 的路径;

httpOnly 用来设置是否允许浏览器中修改 cookie,如果通过浏览器修改设置过 httpOnly=true 的 cookie,则会增加一条同名 cookie,原来的 cookie 不会被修改;

Expires 用来设置过期时间,绝对时间,值为一个 GMT 或 UTC 格式的时间;

max-age 同样用来设置过期时间,相对时间,值为一个正整数,单位 s。

cookie 默认不支持存储中文,如果存储中文需先使用 encodeURIComponent 方法进行转译,将转译后的结果存入 cookie,在浏览器获取 cookie 需使用 decodeURIComponent 方法转回中文。

2、Koa 中操作 cookie

Koa 是当下流行的 NodeJS 框架,是对原生 Node 的一个轻量的封装,但是内部实现了快捷操作 cookie 的方法,下面是原生中对 cookie 的操作在 Koa 中的写法。

// Koa 中操作 cookie

const Koa = require("koa");

const Router = require("koa-router");

// 创建服务和路由

const app = new Koa();

const router = new Router();

// 签名需要设置 key

app.keys = ["shen"];

router.get("/read", (ctx, next) => {

// 获取 cookie

let name = ctx.cookies.get(name) || "No name";

let name = ctx.cookies.get(age) || "No age";

ctx.body = `${name}-${age}`;

});

router.get("/write", (ctx, next) => {

// 设置 cookie

ctx.cookies.set("name", "panda", { domain: "panda.com" });

ctx.cookies.set("age", 28, { maxAge: 10 * 1000, signed: true });

});

// 使用路由

app.use(router.routes());

app.listen(3000);

在 Koa 中将获取和设置 cookie 的方法都挂在了 ctx 上下文对象的 cookies 属性上,分别为 get 和 set。

cookies.get 的参数为获取 cookie 的键名,返回值为键对应的值,cookies.set 的第一个参数同样为 cookie 的键名,第二个参数为键对应的值,第三个参数为一个对象,用来配置该条 cookie 的规则,如 domain、path 和过期时间等,这里 maxAge 值为毫秒数。

注意:Koa 中设置的 cookie 默认不允许浏览器端通过 document.cookie 获取,但是服务器也可以被欺骗,比如使用 postman 发送一个带 Cookie 请求头的请求,服务器可以通过设置签名来预防,即添加 signed 选项并将值设置为 true。

3、Koa 操作 cookie 方法的原理

cookies 对象都是挂在 ctx 上来实现的,使用过 Koa 都知道如果要操作 ctx 就会用到中间件的思想,我们这就看看这两个方法使用原生封装的过程。

// Koa 中 ctx.cookies 对象 get 和 set 方法的原理

const Koa = require("koa");

const querystring = require("querystring");

const app = new Koa();

app.use(async (ctx, next) => {

// 获取 cookie

const get = key => {

let cookies = ctx.get("cookie") || "";

return querystring.parse(result, "; ")[key];

};

// 设置 cookie,存储所有的 cookie,等于 setHeader 中的第二个参数

let cookies = [];

const set = (key, val, options = {}) => {

// 用于构造单条 cookie 和权限等设置的数组,默认存放这条 cookie 的键和值

let single = [`${key}=${encodeURIComponent(val)}`];

// 下面是配置

if (options.domain) {

arr.push(`domain=${options.domain}`);

}

if (options.maxAge) {

arr.push(`Max-Age=${options.maxAge}`);

}

if (options.path) {

arr.push(`path=${options.path}`);

}

if (options.httpOnly) {

arr.push(`HttpOnly=true`);

}

// 将配置组合到 single 中后转为字符串存入 cookies

cookies.push(single.join("; "));

// 设置给浏览器

ctx.set("Set-Cookie", cookies);

}

// 将获取和设置 cookie 的方法挂在 cookies 对象上

ctx.cookies = { get, set };

await next();

});

在 get 方法内部获取 cookie 请求头的值并根据传入的 key 获取值,set 方法内,将传入的键值和选项拼接成符合 cookie 的字符串,通过 Set-Cookie 响应头设置给浏览器。

session 的基本使用

1、NodeJS 原生使用 session

正常 session 是存放在数据库中的,我们这里为了方便就用一个名为 session 的对象来代替。

// 原生中使用 session

const http = require("http");

const uuid = require('uuid/v1'); // 生成随字符串

const querystring = require("querystring");

// 存放 session

const session = {};

// 创建服务

http.createServer((req, res) => {

if (req.url === "/user") {

// 取出 cookie 存储的用户 ID

let userId = querystring.parse(req.headers["cookie"], "; ")["study"];

if (userId) {

if (session[userId].studyCount === 0) res.end("您的学习次数已用完");

session[userId].studyCount--;

} else {

// 生成 userId

userId = uuid();

// 将用户信息存入 session

session[userId] = { studyCount: 30 };

// 设置 cookie

req.setHeader("Set-Cookie", [`study=${userId}`]);

}

// 响应信息

res.end(`

您的用户 ID 为 ${userId},

剩余学习次数为:${session[userId].studyCount}

`);

} else {

res.end("Not Found");

}

}).listen(3000);

上面写的案例是一个网校的场景,一个新用户默认有 30 次学习机会,以后每次访问服务器学习次数减 1,如果 studyCount 值为 0,则提示学习次数用完,否则提示当前用户的 ID 和剩余学习次数,session 中存储的是每一个用户 ID 对应的剩余学习次数,这样就不会轻易的被修改学习剩余次数,因为服务器只认用户 ID,再通过 ID 去更改对应的剩余次数(当然忽略了别人冒充这个 ID 的情况,只能减,不能加),这样就不会因为篡改 cookie 而篡改用户存在 session 中的数据,除非连整个数据库都拖走。

2、Koa 中使用 session

我们接下来使用 Koa 实现和上面一摸一样的场景,在 Koa 的社区中提供了专门操作 session 的中间件 koa-session,使用前需安装。

// Koa 中使用 session

const Koa = require("koa");

const Router = require("koa-router");

const session = requier("koa-session");

const uuid = require("uuid/v1");

// 创建服务和路由

const app = new Koa();

const router = new Router();

// cookie 的签名

app.keys = ["panda"];

// 使用 koa-session 中间件

app.use(session({

key: "shen",

maxAge: 10 * 1000

}, app));

router.get("/user", (ctx, next) => {

// 取出 cookie 存储的用户 ID

let userId = ctx.cookie("study");

if (ctx.session.userId) {

if (ctx.session[userId].studyCount === 0) res.end("您的学习次数已用完");

ctx.session[userId].studyCount--;

} else {

// 生成 userId

userId = uuid();

// 将用户信息存入 session

ctx.session[userId] = { studyCount: 30 };

// 设置 cookie

ctx.cookies.set("study", userId);

}

// 响应信息

ctx.body = `

您的用户 ID 为 ${userId},

剩余学习次数为:${session[userId].studyCount}

`;

});

// 使用路由

app.use(router.routes());

app.listen(3000);

使用 Koa 的 koa-session 以后,不再需要我们创建 session 对象进行存储,并且 cookie-session 中间件帮我们封装了 API 可以直接操作 mongo 和 MySQL 数据库,上面代码中与用原生相比还增加了 cookie 和 session 的签名和过期时间,比原生写起来要方便很多。

总结

本篇内容更偏向于 cookie 和 session 在 NodeJS 中的使用,没有过多的叙述理论性的内容,cookie 和 session 是相互依存的,也就是说共同使用的,现在已经有 JWT 的方案来替代,因为相比较下有很多优点,但某些项目和特殊场景还在使用 cookie 和 session,所以还是写了这一篇,如果对 JWT 感兴趣可以看 通过一个案例理解 JWT。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值