背景
本文将介绍 Nodejs 相关技术,让更多前端技术人员突破技术壁垒,向全栈靠拢
尝试坚持学习新技术、写技术文章,学而时习之,不亦说乎!
1、一叶障目,不见泰山,对技术怀有一颗敬畏之心
2、脚踏实地,一步一个脚印,最后肯定有回报
3、水滴石穿、熟能生巧,多敲多 debug
初始 cookie
在大多数 Web 应用中,能依靠请求路径和请求参数来做大部分的工作,但是 HTTP 是一个无状态的协议,但是有些业务是需要一定的状态来区分不同用户之间的身份。最早的用来区别所用的技术就是 Cookie (曲奇饼)
Cookie 最早由文本浏览器 Lynx 合作开发者 Liu Montulli 在 1994 年网景公司开发 Netscape 浏览器的第一个版本时发明。它能记录服务器与客户端之间的状态,最早的用处就是用来判断用户是否第一次访问网站。在 1997 年形状规范 RFC 2109, 目前最新的规范为 RFC 6265, 它是一个由浏览器和服务器共同协作实现的规范
Cookie 的处理有以下几步
- 服务器向客户端发送 Cookie
- 浏览器将 Cookie 保存(保存在本地,小文本文件)
- 之后每次浏览器发起请求时,都会将 Cookie 放请求头传给服务器
浏览器查看 Cookie
根据实际情况,查看到 Cookie 值得格式是 key=value; key2=value2, ... 形式的,因为要达到易用效果,我们要做封包和解包两部分代码
开始动手
目录结构
├── ch8
│ ├── 8.1.4Cookie.js
├── package.json
├── index.js
代码内容
// ./ch8/8.1.4Cookie.js
/**
* 解包, 将字符串解析成对象, 挂载到 req 上供后续使用
* @param {*} req
* @param {*} res
* @returns {object}
*/
const parseCookie = (req, res) => {
let cookie = req.headers.cookie;
const cookies = {};
req.cookies = cookies;
if(!cookie) {
return cookies;
}
cookie = cookie.replace(";", "&");
const searchParams = new URLSearchParams(cookie);
const entries = searchParams.entries();
for(const [key, value] of entries) {
cookies[key.trim()] = value;
}
return cookies;
}
/**
* 封包, 将 key、value、cookie options 封装字符串格式
* @param {string} name
* @param {string} val
* @param {object} opt
* @returns {string}
*/
const serialize = (name, val, opts) => {
const pairs = [name + "=" + encodeURIComponent(val)];
opts = opts || {};
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.toUTCString());
if (opt.httpOnly) pairs.push('HttpOnly');
if (opt.secure) pairs.push('Secure');
return pairs.join("; ");
}
module.exports = {
parseCookie,
serialize
}
// ./index.js
const http = require("http");
const { parseCookie, serialize } = require("./ch8/8.1.4Cookie.js");
const _headers = {
"Content-Type": "text/html; charset=UTF-8"
}
const server = http.createServer((req, res) => {
parseCookie(req, res);
handle(req, res);
});
const handle = (req, res) => {
const cookies = req.cookies;
if(!cookies.isVisit) {
/*
* 第一次请求,没有携带对应的 cookie,
* 服务器向客户端发送 cookie, 客户端收到后, 会保存到本地
* 下次请求会将保存的 cookie 放请求头携带给服务器
*/
res.setHeader("Set-Cookie", serialize("isVisit", "1"));
res.writeHead(200, Object.assign(_headers));
res.end("欢迎第一次访问");
} else {
res.writeHead(200, Object.assign(_headers));
res.end("欢迎再次访问");
}
}
// 监听 9527 端口
server.listen(9527, "127.0.0.1");
执行命令
node ./index.js
浏览器访问
http://127.0.0.1:9527
浏览器表现(第一次访问)
请求头没有携带 cookie 信息到服务器
响应头携带 Set-Cookie:isVisit=1 给浏览器, 浏览器会保存到本地
浏览器表现(第二次访问)
请求头携带 Cookie:isVisit=1 给服务器
F12控制台 --> Application --> Storage --> Cookies 可以查看到本地保存了哪些值
补充
Cookie 格式
Set-Cookie: name=value; Path=/; Expires=Sun, 23-Apr-23 09:01:35 GMT; Domain=.domain.com;
- path 表示这个 cookie 影响到的路径,当前访问的路径不满足该匹配时,浏览器则不发送这个 Cookie
- Expires 和 Max-Age 标识这个 cookie 何时过期,如果不设置,则是会话级别的,即关闭浏览器就会删除这个 cookie, 如果设置了过期时间, 浏览器会把 cookie 内容写到磁盘中并保存
- HttpOnly 告知浏览器不允许通过脚本 document.cookie 去更改这个 Cookie 值,实时上,设置 HttpOnly 之后,这个值在 document.cookie 中不可见。但是在 HTTP 请求的过程中,依然会发送这个 Cookie 到服务器端。
- Secure 当设置为 true 时候,在 HTTP 中是无效的,在 HTTPS 中才有效
Cookie 的性能影响
虽然 Cookie 解决了 HTTP 无状态的燃眉之急,但是也有它的弊端,由于浏览器每次请求都会发送本地储存的 Cookie 到服务器端,一旦设置的 Cookie 过多,将会导致报头较大。大多数的 Cookie 并不需要每次都用得上,因为这会浪费部分宽带。最为严重的问题就是可以在前端直接修改,因此数据就极容易篡改和伪造。
下一篇 Session 将优化以上的问题