node
# Node 介绍
# 为什么要学习 Node.js
- 企业需求
- 具有服务端开发经验更改
- front-end
- back-end
- 全栈开发工程师
- 基本的网站开发能力
- 服务端
- 前端
- 运维部署
- 多人社区
# Node 能做什么
- web 服务器后台
- 命令行工具
- npm(node)
- git (c 语言)
- hexo(node)
- ...
- 对于前端工程师来讲,接触最多的是它的命令行工具
- 自己写的很少,主要是用别人第三方的
- webpack
- gulp
- npm
# 起步
# 安装 Node 环境
下载:https://nodejs.org/en/
确认 Node 环境是否安装成功
node -v配置环境变量
# 解析执行 JavaScript
- 创建编写 JavaScript 脚本文件
- 打开终端,定位脚本文件的所属目录
- 输入
node 文件名执行对应的文件
注意:文件名不要用 node.js 来命名,也就是说除了 node 这个名字随便起,最好不要使用中文。
# Buffer 的使用
# 创建 Buffer
// 创建一个指定size大小的Buffer
var buf = Buffer.alloc(size); //安全,里面全是0
var buf = Buffer.allocUnsafe(size); //不安全,可能包含旧数据,需要重写所有数据
// 获取Buffer的长度
buf.length
2
3
4
5
6
7
# 转换
// 相当于Buffer.alloc(size);
var buf = Buffer.allocUnsafe(size);
buf.fill(0) //将可能出现的敏感数据用0全部填充
// 将一个字符串转换为Buffer
var buf = Buffer.from(str);
// 将一个Buffer转换为字符串
var str = buf.toString();
2
3
4
5
6
7
8
9
10
# fs 文件系统
全称为 file system,所谓的文件系统,就是对计算机中的文件进行增删改查等操作。它是一个服务器的基础,在 Node 中通过 fs 模块来操作文件系统。
# fs 的使用
fs模块是Node的核心模块,不需要下载,直接引入即可使用
const fs = require("fs");
fs中的大部分方法都为我们提供了两个版本:
a. 同步方法:带 sync 的方法
a) 同步方法会阻塞程序的执行
b) 同步方法通过返回值返回结果
b. 异步方法:不带 sync 的方法
a) 异步方法不会阻塞程序的执行
b) 异步方法都是通过回调函数来返回结果的
# 文件的写入
# 简单写入
同步方法:fs.writeFileSync(file, data[, options])
异步方法:fs.writeFile(file, data[, options], callback)
参数:
file 要写入的文件的路径
data 要写入的内容,可以是一个String也可以是一个Buffer
options 配置对象,需要一个对象作为参数,默认如下:
{encoding:"utf8",flag:"w",mode:0666}
--encoding:设置文件的编码方式,默认值:utf8(万国码)
--mode:设置文件的操作权限,默认值是:0o666 = 0o222 + 0o444
--0o111:文件可被执行的权限
--0o222:文件可被写入的权限
--0o444:文件可别读取的权限
--flag:打开文件要执行的操作,默认值是'w'
--a :追加
--w :写入
callback 回调函数
--err:错误对象
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//引入内置的fs模块
let fs = require('fs')
//调用writeFile方法
fs.writeFile(__dirname+'/demo.txt','kobe,123',err => {
if(err) console.log('文件写入失败',err)
else console.log('文件写入成功')
})
2
3
4
5
6
7
8
# 流式写入
流式文件写入适用于一些比较大的文件,可以分多次向文件中写入内容,有效避免内存溢出的问题
1.创建一个可写流
var ws = fs.createWriteStream(path);
2.监听流的状态
ws.once("open",function(){});
ws.once("close",function(){});
3.向流中写入内容
ws.write(...);
ws.write(...);
ws.write(...);
4.关闭流
ws.end();
2
3
4
5
6
7
8
9
10
11
12
# 文件的读取
# 简单读取文件
fs.readFileSync(path[, options])
fs.readFile(path[, options], callback)
参数:
path 读取文件的路径
options 配置对象
encoding 指定打开文件的编码,默认是null
flag 文件的操作类型,默认是 r
callback 回调函数,通过回调函数返回读取到的数据
err 错误对象
data 返回的数据(Buffer)
2
3
4
5
6
7
8
9
10
11
# 流式读取文件
适合较大的文件
// 方式一:
//创建一个可读流
var rs = fs.createReadStream("C:\\other\\MP3\\笔记.mp3");
//创建一个可写流
var ws = fs.createWriteStream("biji.mp3");
//监听可读流,可读流读取完毕后会自动关闭
rs.once("open" , function () {
console.log("流打开了");
});
rs.once("close" , function () {
console.log("流关闭了");
//数据读取完毕,可以关闭可写流
ws.end();
});
//监听可写流
ws.once("open" , function () {
console.log("可写流打开了");
});
ws.once("close" , function () {
console.log("可写流关闭了");
});
//要通过可读流读取一个文件,必须为流绑定一个data事件,当绑定了data事件以后,流会自动读取
rs.on("data",function (data) {
//console.log(data);
//将数据写入到可写流中
ws.write(data);
});
//方式二:
//创建一个可读流
var rs = fs.createReadStream("C:\\other\\MP3\\笔记.mp3");
//创建一个可写流
var ws = fs.createWriteStream("biji.mp3");
/*
pipe()
- 可以将一个可读流中的内容写入到一个可写流中
*/
rs.pipe(ws);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# http
http 搭建服务器服务器:
// 1.加载http核心模块
const http=require("http");
// 2.使用http.createServer()创建一个web服务器
let server=http.createServer(function (request,response) {
response.end("ok")
})
// 4.绑定端口号,启动服务
server.listen(3000,function(){
console.log('runing...')
})
2
3
4
5
6
7
8
9
10
11
12
# 模块标识符中的 / 和文件操作路径中的 /
文件操作路径:
// 咱们所使用的所有文件操作的API都是异步的
// 就像ajax请求一样
// 读取文件
// 文件操作中 ./ 相当于当前模块所处磁盘根目录
// ./index.txt 相对于当前目录
// /index.txt 相对于当前目录
// /index.txt 绝对路径,当前文件模块所处根目录
// d:express/index.txt 绝对路径
fs.readFile('./index.txt',function(err,data){
if(err){
return console.log('读取失败');
}
console.log(data.toString());
})
2
3
4
5
6
7
8
9
10
11
12
13
14
模块操作路径:
// 在模块加载中,相对路径中的./不能省略
// 这里省略了.也是磁盘根目录
require('./index')('hello')
2
3
# npm,cnpm,yarn
- node package manage (node 包管理器)
- 通过 npm 命令安装 jQuery 包(npm install --save jquery),在安装时加上 --save 会主动生成说明书文件信息(将安装文件的信息添加到 package.json 里面)
# npm 命令行工具
npm 是一个命令行工具,只要安装了 node 就已经安装了 npm。
npm 也有版本概念,可以通过 npm --version 来查看 npm 的版本
升级 npm (自己升级自己):
npm install --global npm
# 常用命令
npm init -y //可以跳过向导,快速生成
npm install //一次性把dependencies选项中的依赖项全部安装
npm i //简写
2
npm install 包名 //下载第三方包
npm install --save 包名 //下载并且保存依赖项(package.json文件中的dependencies选项)
npm uninstall 包名 //只删除,如果有依赖项会依然保存
npm uninstall --save 包名 //删除的同时也会把依赖信息全部删除
# 解决 npm 被墙问题
###1. 国内使用 npm 存在的问题
npm 的远程服务器在国外,所以有时候难免出现访问过慢,甚至无法访问的情况。
npm config get registry //查看当前npm远程仓库地址
###2. 使用淘宝的 cpm 代替 npm
#### 第一种使用方法:直接安装 cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
#### 第二种使用方法:替换 npm 仓库地址为淘宝镜像地址
npm config set registry https://registry.npm.taobao.org
###3. 使用 yarn 代替 npm
npm install yarn -g //全局安装yarn
#### 第二种使用方法:替换 yarn 仓库地址为淘宝镜像地址
yarn config set registry https://registry.npm.taobao.org
# yarn 常用命令
yarn --version //查看yarn版本
yarn init //生成package.json !!!注意生成的包名不能有中文,大写
yarn global package //全局安装
yarn add package //局部安装
yarn add package --dev //相当于npm中的--save-dev
yarn remove package //移除包
yarn list //列出已经安装的包名
yarn info package //获取包的有关信息
yarn //安装package.json中的所有依赖
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# path 路径操作模块
参考文档:https://nodejs.org/docs/latest-v13.x/api/path.html
- path.basename:获取路径的文件名,默认包含扩展名
- path.dirname:获取路径中的目录部分
- path.extname:获取一个路径中的扩展名部分
- path.parse:把路径转换为对象
- root:根路径
- dir:目录
- base:包含后缀名的文件名
- ext:后缀名
- name:不包含后缀名的文件名
- path.join:拼接路径
- path.isAbsolute:判断一个路径是否为绝对路径

# Node 中的其它成员 (__dirname,__filename)
__dirname //可以用来**动态**获取当前文件模块所属目录的绝对路径
__filename //可以用来**动态**获取当前文件的绝对路径(包含文件名)
在拼接路径的过程中,为了避免手动拼接带来的一些低级错误,推荐使用 path.join() 来辅助拼接
var fs = require('fs');
var path = require('path');
// console.log(__dirname + 'a.txt');
// path.join方法会将文件操作中的相对路径都统一的转为动态的绝对路径
fs.readFile(path.join(__dirname + '/a.txt'),'utf8',function(err,data){
if(err){
throw err
}
console.log(data);
});
2
3
4
5
6
7
8
9
10
# 第 1 章:Express 简介
# 1.1 Express 是什么
Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你快速创建各种 Web 和移动设备应用。
简单来说 Express 就是运行在 node 中的用来搭建服务器的模块。
# 1.2 Express 的使用
# 1.2.1 下载
npm i express --save //使用npm安装express并添加到依赖项
yarn add express //使用yarn安装express并添加到依赖项
2
# 1.2.2 第一个服务器
//1.引入express模块
const express=require("express")
//2.创建应用对象
const app = express()
//3.配置路由
app.get("/index",function (request,response) {
//接受地址栏发送的请求,格式为对象
console.log(request.query)
//设置响应
response.send("ok")
})
//4.监听端口
app.listen(3000,function () {
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 第 2 章:路由(Route)
# 2.1 Route 是什么
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
路由是由一个 URI、HTTP 请求(GET、POST 等)和若干个句柄组成的。
# 2.2 Route 的定义
我们可以将路由定义为三个部分:
第一部分:HTTP 请求的方法(get 或 post)
第二部分:URI 路径
第三部分:回调函数
# 2.3 Route 的实现
Express 中提供了一系列函数,可以让我们很方便的实现路由:
app.<method>(path,callback)
//method指的是HTTP请求方法,比如: app.get() app.post(),express中app.all()方法,可以处理两种请求
//path指要通过回调函数来处理的URL地址
//callback参数是应该处理该请求并把响应发回客户端的请求处理程序
2
3
4
# 2.4 Request 对象
# Request 对象属性和方法
| ** 属性 /** 方法 | 描述 |
|---|---|
| request.query | 获取 get 请求查询字符串的参数,拿到的是一个对象 |
| request.params | 获取 get 请求参数路由的参数,拿到的是一个对象 |
| request.body | 获取 post 请求体,拿到的是一个对象(要借助一个中间件) |
| request.get(xxxx) | 获取请求头中指定 key 对应的 value |
# 2.5 Response 对象
# Response 对象的属性和方法
| ** 属性 /** 方法 | 描述 |
|---|---|
| response.send() | 给浏览器做出一个响应 |
| response.end() | 给浏览器做出一个响应(不会自动追加响应头) |
| response.download() | 告诉浏览器下载一个文件 |
| response.sendFile() | 给浏览器发送一个文件 |
| response.redirect() | 重定向到一个新的地址(url) |
| response.set(header,value) | 自定义响应头内容 |
| response.get() | 获取响应头指定 key 对应的 value |
| res.status(code) | 设置响应状态码 |
# 2.6 路由实例
const express = require("express")
let app = express()
app.get("/", function (request, response) {
//接受地址栏发送的请求,格式为对象
// console.log(request.params);
//console.log(request.params)
//response.send("ok")
// response.download("./demo.zip")
// response.redirect("https://www.baidu.com")
})
app.listen(3000, function () {
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
# 第 3 章:中间件
# 3.1 中间件简介
概念:本质上就是一个函数,包含三个参数:request、response、next
# 3.2 中间件功能
执行任何代码。修改请求和响应对象。终结请求-响应循环。调用堆栈中的下一个中间件。
# 3.3 中间件的分类
1) 应用(全局)级中间件(过滤非法的请求,例如防盗链)
--第一种写法:app.use((request,response,next)=>{})
--第二种写法:使用函数定义
2) 第三方中间件,即:不是Node内置的,也不是express内置的(通过npm下载的中间件,例如body-parser)
--app.use(bodyParser.urlencoded({extended:true}))
3) 内置中间件(express内部封装好的中间件)
--app.use(express.urlencoded({extended:true}))
--app.use(express.static('public')) //暴露静态资源
4) 路由器中间件 (Router)
2
3
4
5
6
7
8
9
# 3.4 中间件实例
# 3.4.1 应用级
const express = require("express")
let app = express()
/*【第一种】使用应用级(全局)中间件------所有请求的第一扇门
-------所有请求都要经过某些处理的时候用此种写法*/
app.use((request,response,next)=>{
response.send("全局中间件")
next() //跳过此中间件,到下一个中间件或下一个路由
})
app.get("/", function (request, response) {
response.send("index")
})
app.get("/login", function (request, response) {
response.send("login")
})
app.get("/register", function (request, response) {
response.send("register")
})
app.listen(3000, function () {
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//第二种写法:使用函数定义
const express = require("express")
let app = express()
function guard(request,response,next){
response.send("函数中间件")
}
app.get("/", function (request, response) {
response.send("index")
})
//在此路由上添加中间件,就不会拦截所有的路由了,guard是自己定义的函数
app.get("/login", guard,function (request, response) {
response.send("login")
})
app.get("/register", function (request, response) {
response.send("register")
})
app.listen(3000, function () {
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 3.4.2 内置中间件 (处理 request.body)
const express = require("express")
let app = express()
// 解析post请求请求体中所携带的urlencoded编码形式的参数为一个对象,随后挂载到request对象上
app.use(express.urlencoded({extended:true}))
app.get("/", function (request, response) {
response.send("index")
})
app.post("/login",function (request, response) {
console.log(request.body)
response.send("login")
})
app.get("/register", function (request, response) {
response.send("register")
})
app.listen(3000, function () {
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 暴露静态资源
const express = require("express")
let app = express()
//将public中的静态文件暴露出去,避免了使用多个路由
app.use(express.static(__dirname+"/public"))
app.get("/", function (request, response) {
response.send("index")
})
app.listen(3000, function () {
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
# 第 4 章:Router 路由器
# 4.1 Router 是什么
Router 是一个完整的中间件和路由系统,也可以看做是一个小型的 app 对象。
# 4.2 为什么使用 Router
为了更好的分类管理 route
# 4.3 Router 的使用
//创建路由器
const {Router}=require("express")
let router=new Router()
//使用路由
router.app("/",()=>{})
router.use()
2
3
4
5
6
# 第 5 章:EJS 模板
EJS 是一个高效的 JavaScript 模板引擎,动态渲染数据,使得前后端分离,是基于 express 的
# 5.1 使用 EJS
使用 ejs 前必须有 express 模版
下载安装
npm i ejs -S
yarn add ejs -S
2
配置模板引擎
app.set("view engine" , "ejs")
配置模板的存放目录(目录为后面的)
app.set("views","./views")
在views目录下创建模板文件
模板名称.ejs
使用模板,通过response来渲染模板
response (‘模板名称’, 数据对象)
# 5.2 EJS 语法
ejs 语法:
1.<% %> 里面能写任意 js 代码,但是不会向浏览器输出任何东西。
2.<%- %> 能够将后端传递过来对象指定 key 所对应 value 渲染的页面, 渲染 html 标签
3.<%= %> 能够将后端传递过来对象指定 key 所对应 value 渲染的页面不渲染 html 标签
# 5.3 EJS 具体使用
server.js
const express=require("express")
const app=express()
//配置模版引擎
app.set("view engine","ejs")
//配置模版路径
app.set("views","./views")
app.get("/",(req,res)=>{
res.render("index",{data:"hello"})
})
app.listen(3000,()=>{
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
index.ejs
<%-data%>
# 第 6 章:art-templete 模版的使用
在 node 中,有很多第三方模板引擎都可以使用,不是只有 art-template ,还有 ejs,jade(pug),handlebars,nunjucks
# 6.1art-templete 的使用
npm install --save art-template
npm install --save express-art-template
//1.两个一起安装
npm i --save art-template express-art-template
//2.引用art-template模版,第一个参数设置后缀名
app.engine('html', require('express-art-template'));
//3.使用art-template
app.get('/',function(req,res){
// express默认会去views目录找index.html(如果希望修改默认的`views`视图渲染存储目录,可以使用app.set('views',目录路径)来修改,第一个参数views千万不要修改;)
res.render('index.html',{
title:'hello world'
});
})
2
3
4
5
6
7
8
9
10
11
12
13
14
# 6.2 子模板和模板的继承(模板引擎高级语法)【include,extend,block】
模板页:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>模板页</title>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css"/>
{{ block 'head' }}{{ /block }}
</head>
<body>
<!-- 通过include导入公共部分 -->
{{include './header.html'}}
<!-- 留一个位置 让别的内容去填充 -->
{{ block 'content' }}
<h1>默认内容</h1>
{{ /block }}
<!-- 通过include导入公共部分 -->
{{include './footer.html'}}
<!-- 公共样式 -->
<script src="/node_modules/jquery/dist/jquery.js" ></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.js" ></script>
{{ block 'script' }}{{ /block }}
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
模板的继承:
header 页面:
<div id="">
<h1>公共的头部</h1>
</div>
2
3
footer 页面:
<div id="">
<h1>公共的底部</h1>
</div>
2
3
模板页的使用:
<!-- 继承(extend:延伸,扩展)模板也layout.html -->
<!-- 把layout.html页面的内容都拿进来作为index.html页面的内容 -->
{{extend './layout.html'}}
<!-- 向模板页面填充新的数据 -->
<!-- 填充后就会替换掉layout页面content中的数据 -->
<!-- style样式方面的内容 -->
{{ block 'head' }}
<style type="text/css">
body{
background-color: skyblue;
}
</style>
{{ /block }}
{{ block 'content' }}
<div id="">
<h1>Index页面的内容</h1>
</div>
{{ /block }}
<!-- js部分的内容 -->
{{ block 'script' }}
<script type="text/javascript">
</script>
{{ /block }}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 第 7 章:会话控制
# 7.1 会话控制是什么
HTTP 协议是一个无状态的协议,它无法区分多次请求是否发送自同一客户端。
# 7.2 cookie
# 7.2.1 cookie 是什么
关于 cookie:
1. 是什么?
本质就是一个【字符串】,里面包含着浏览器和服务器交互的信息。
存储的形式以:【key-value】的形式存储。
浏览器会自动携带该网站的 cookie,只要是该网站下的 cookie,全部携带。
分类:
会话 cookie(关闭浏览器后,会话 cookie 会自动消失,会话 cookie 存储在浏览器运行的那块【内存】上)。
持久化 cookie:(看过期时间,一旦到了过期时间,自动销毁,存储在用户的硬盘上,备注:如果没有到过期时间,同时用户清理了浏览器的缓存,持久化 cookie 也会消失)。
3. 工作原理:
当浏览器第一次请求服务器的时候,服务器可能返回一个或多个 cookie 给浏览器,当浏览器以后请求该网站的时候,自动携带上该网站的所有 cookie(无法进行干预),并判断 cookie 种类,服务器拿到之前自己 “种” 下 cookie,分析里面的内容,校验 cookie 的合法性,根据 cookie 里保存的内容,进行具体的业务逻辑。
4. 应用:
解决 http 无状态的问题(一般来说不会单独使用 cookie,一般配合后台的 session 存储使用)
5. 不同的语言、不同的后端架构 cookie 的具体语法是不一样的,但是 cookie 原理和工作过程是不变的。
备注:cookie 不一定只由服务器生成,前端同样可以生成 cookie,但是前端生成的 cookie 几乎没有意义。
# 7.2.2 cookie 的不足
各个浏览器对 cookie 的数量和大小都有不同的限制,这样就导致我们不能在 Cookie 中保存过多的信息。一般数量不超过 50 个,单个大小不超过 4kb。
cookie 是由服务器发送给浏览器,再由浏览器将 cookie 发回,如果 cookie 较大会导致发送速度非常慢,降低用户的体验。
# 7.2.3 cookie 的使用
在 node 中 express 库下使用 cookie
1. 创建 cookie
const express=require("express")
const app=express()
//创建一个回话cookie(cookie必须以键值对的字符串传递)
app.get("/demo1",(req,res)=>{
let obj={name:"zhangsan"}
res.cookie("data",JSON.stringify(obj))
res.send("创建一个回话cookie")
})
//创建一个持久化cookie
app.get("/demo2",(req,res)=>{
let obj={name:"lisi"}
res.cookie("data",JSON.stringify(obj),{maxAge:1000*60})
res.send("创建一个持久化cookie")
})
app.listen(3000,()=>{
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2. 读取 cookie, 需要借助第三方中间件 cookie-parser
//下载cookie-parse
npm i cookie-parser --save
2
const express=require("express")
//引入cookie-parser
const cookieParser = require("cookie-parser")
const app=express()
//配置cookieParser
app.use(cookieParser());
//接受浏览器返回的cookie(不区分会话和持久化)
app.get("/demo3",(req,res)=>{
let {data}=req.cookies //注意接收的是req.cookies(不是cookie)
console.log(JSON.parse(data))
res.send("返回cookie到服务器的控制台")
})
app.listen(3000,()=>{
console.log("run")
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3. 修改和删除 cookie
res.cookie("data","hahha"); //可以使用同名的cookie来替换已有cookie
res.cookie("data","",{maxAge:0}); //value为空,maxAge为0
res.clearCookie(“data”) //用来删除一个指定cookie
2
3
# 7.3 session
# 7.3.1 session 是什么
1. 是什么?
后端人员常常把【session 会话存储】简称为:session
2. 特点:
1. 存在于服务端
2. 存储的是浏览器和服务器之间交互产生的一些信息
3. 默认 session 的存储在服务器的内存中,每当一个新客户端发来请求,服务器都会新开辟出一块空间,供 session 会话存储使用。
4. 工作流程:
(1)第一次浏览器请求服务器的时候,服务器会开辟出一块内存空间,供 session 会话存储使用。返回响应的时候,会自动返回一个 cookie(有时候会返回多个,为了安全),cookie 里包含着会话存储的编号(id)
(2)浏览器以后请求的时候,会自动携带这个 cookie,给服务器。服务器从该 cookie 中拿到对应的 session 的 id,去服务器中匹配。
(3)服务器会根据匹配信息,决定下一步逻辑
5. 备注:
1. 一般来说 cookie 一定会配合 session 使用。
2. 服务端一般会做 session 的持久化,防止由于服务器重启,造成 session 的丢失。
3.session 什么时候销毁?
(1). 服务器没有做 session 的持久化的同时,服务器重启了。
(2). 给客户端种下的那个用于保存 session 编号的 cookie 销毁了,随之服务器保存的 session 销毁 (不管是否做了 session 的持久化)。
(3). 用户主动在网页上点击了 “注销” “退出登录” 等等按钮。
# 7.3.2 session 运作流程
我们可以在服务器中为每一次会话创建一个对象,然后每个对象都设置一个唯一的 id,并将该 id 以 cookie 的形式发送给浏览器,然后将会话中产生的数据统一保存到这个对象中,这样我们就可以将用户的数据全都保存到服务器中,而不需要保存到客户端,客户端只需要保存一个 id 即可。
# 7.3.3 session 的使用
下载安装
npm i connect-mongo express-session --save
引入模块
var session = require("express-session");
将其配置为express-session的默认的持久化仓库
var MongoStore = require('connect-mongo')(session);
设置为中间件
app.use(session({
name: 'id22', //设置cookie的name,默认值是:connect.sid
secret: 'atguigu', //参与加密的字符串(又称签名)
saveUninitialized: false, //是否为每次请求都设置一个cookie用来存储session的id
resave: true ,//是否在每次请求时重新保存session
store: new MongoStore({
url: 'mongodb://localhost:27017/test-app',
touchAfter: 24 * 3600 // 24小时之内只修改一次
}),
cookie: {
httpOnly: true, // 开启后前端无法通过 JS 操作
maxAge: 1000*30 // 这一条 是控制 sessionID 的过期时间的!!!
},
}));
2
3
4
5
6
7
8
9
10
11
12
13
14
# 7.3.4 cookie 和 session 的区别
存在的位置:
cookie 存在于客户端,临时文件夹中
session 存在于服务器的内存中,一个 session 域对象为一个用户浏览器服务
安全性:
cookie 是以明文的方式存放在客户端的,安全性低,可以通过一个加密算法进行加密后存放
session 存放于服务器的内存中,所以安全性好
网络传输量:
cookie 会传递消息给服务器
session 本身存放于服务器,但是通过 cookie 传递 id,会有少量的传送流量
生命周期(以20分钟为例):
cookie 的生命周期是累计的,从创建时,就开始计时,20 分钟后,cookie 生命周期结束
session 的生命周期是间隔的,从创建时,开始计时如在 20 分钟,没有访问 session,那么 session 生命周期被销毁;但是,如果在 20 分钟内(如在第 19 分钟时)访问过 session,那么,将重新计算 session 的生命周期;关机会造成 session 生命周期的结束,但是对 cookie 没有影响
访问范围:
session 为一个用户浏览器独享
cookie 为多个用户浏览器共享
大小:
cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 50 个 cookie
session 保存数据理论上没有任何限制(内存有多大就能有多大)