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 保存数据理论上没有任何限制(内存有多大就能有多大)