侧边栏壁纸
博主头像
Angel博主等级

行动起来,活在当下

  • 累计撰写 20 篇文章
  • 累计创建 8 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

Node

Angel
2023-07-15 / 0 评论 / 0 点赞 / 86 阅读 / 64592 字
温馨提示:
本文最后更新于 2023-07-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

一、内置方法

***fs模块

方法 **​

  • fs.readFile()方法

    读取指定文件中的内容

    const fs = require('fs')
    fs.readFile('文件的路径','utf8',function(err,dataStr) {})
    
  • fs.writeFile()方法

    指定文件中写入的内容

    const fs = require('fs')
    fs.writeFile('111.txt', 'abcd', function(err) {
        console.log(err);
        //写入成功err为空
    })
    
  • 路径问题

    路径拼接错误 是因为提供了相对路径

    路径相对于执行文件的终端的所在路径

    ##解决

    1. 绝对路径:拼接一个带盘符的路径(移植性差,不利于维护)
    2. __dirname 当前文件所处的目录 拼接要执行的js文件的名称

***path模块

**方法

  • path.join()方法

    将多个路径片段拼接成一个完整的路径字符串

const path = require('path')
const pathStr = path.join('/a', '/b/c', '../', '/d', '/e')
console.log(pathStr);
  • path.basename()方法

    获取文件名称

  • path.extname()方法

    获取文件的后缀名

*replace字符串的替换 可以跟正则表达式来替换正则表达式匹配的字符串

**注意

  1. fs.writeFile() 只能用来创建文件,不能用来创建路径
  2. 重复调用fs.writeFile() 新写的内容会覆盖之前的旧内容

***http模块

**ip地址

  • 每台计算机唯一确定的地址
  • ping xxx地址 ——查看某个地址的ip地址
  • 以192.168开头的是私有地址
  • 最大是255
  • 127.0.0.1 / localhost ——表示自己的电脑(都能访问自己的电脑)

**域名和域名服务器

  • 域名:帮助我们记忆
  • 域名服务器:提供ip地址和域名之间的转换的服务器
  • DNS域名解析服务器

**端口号

客户端发来的网络请求 通过端口号 可以被准确的交给对应的web服务进行处理

##http协议 默认端口为80 https默认端口 443

**创建web服务器的模块基本步骤

  1. 导入http
  2. 创建 web 服务器实例
  3. 为服务器实例绑定 request 事件,监听客户端的请求
  4. 启动服务器
  5. node命令访问服务器
//导入http
const http = require('http')
//创建 web 服务器实例
const server = http.createServer()
//为服务器实例绑定 request 事件,监听客户端的请求
server.on('request',function(req,res) {
    //有请求 就会触发 request 事件
    console.log('Someone visit our web server')
})
//启动服务器(端口的绑定)
server.listen(8080,function() {
  //第一个参数是 端口号
  console.log('服务器启动了')
}) 

**req 请求对象

可以得到请求相关的信息

  • req 是请求对象 包含与客户端相关的数据和属性
  • req.url 是客户端请求的 URL 地址
  • req.method 客户端的请求类型

**res 响应对象

  • res.end() 向客户端响应一些内容 并结束这次请求的处理过程

** 解决中文乱码的问题

设置 Content-Type 响应头

//用utf-8的形式对代码进行解析
res.setHeader('Content-Type','text/html;charset = utf-8')
  • 时钟案例
    const http = require('http')
    const server = http.createServer()
    const fs = require('fs')
    const path = require('path')
    server.on('request', function(req, res) {
        var fileName = req.url
        if (fileName === '/') {
            fileName = 'index.html'
        }
        //简化代码
        fs.readFile(path.join(__dirname, fileName), 'utf8', function(err, dataStr) {
                if (err) {
                    return res.end('Not Found')
                }
                res.end(dataStr)
            })
            //分开写   加深理解
            // if (req.url === '/' || req.url == '/index.html') {
            //     fs.readFile(path.join(__dirname, '/index.html'), 'utf8', function(err, dataStr) {
            //         res.end(dataStr)
            //     })
            // } else if (req.url === '/index.css') {
            //     fs.readFile(path.join(__dirname, '/index.css'), 'utf8', function(err, dataStr) {
            //         res.end(dataStr)
            //     })
            // } else if (req.url === '/index.js') {
            //     fs.readFile(path.join(__dirname, '/index.js'), 'utf8', function(err, dataStr) {
            //         res.end(dataStr)
            //     })
            // }
    })
    server.listen(9919, function() {
        console.log('启动了');
    })
    

二、模块化

***加载模块

//加载内置的 fs 模块
const fs = require('fs')
//加载用户的自定义模块
const custom = require('./相对路径')
//加载第三方模块
const moment = require('moment')

##require

  • 帮助我们引入一个js文件(得到别人提供的东西 就是一个对象)

    得到的是引入模块的 exports 属性

  • 可以使加载模块的代码立即执行

  • 后面不写要加载文件的后缀名 对应文件也能被加载

***模块作用域

  • 在一个模块中定义的变量 不能在另一个模块中使用

##向外共享模块作用域的成员

  • module 对象
    1. .js 自定义模块中都有一个** module **对象,它里面存储了和当前模块有关的信息,
    2. require()方法 导入自定义模块 得到的是 module.exports 所指向的对象
    3. 导入的是 module.exports最后指向的对象为准
    module.exports.obj = obj
    module.exports.fn = fn
    
    //导入的两种形式
    module.exports = {
        obj: obj,
        fn: fn
    }
    
  • exports对象(只是写法更简单了)
    1. exports 和module.exports 指向同一个对象。
    2. exports 和 module.exports 使用是相同的 exports用法更简单

**CommonJS 规范

  1. module变量——当前的文件
  2. module.exports——是对外的接口
  3. require()方法用于加载模块

三、包

***安装包

  • npm install 包的完整名称————安装指定的包
  • npm i 完整的包的名称————简写
  • npm i moment@+版本号————安装指定版本的包
//导入指需要的包
const moment = require('moment')
//查看官方文档 使用包
moment().format('YYYY-MM-DD HH:mm:ss') 

***包管理配置文件

  • package.json——记录项目开发要用到的包
  • 项目开发中,一定要把 node_modules 文件夹 添加到 .gitignore 忽略文件中

##快速创建 package.json 文件

//在执行命令所处的目录中,快速新建 package.json 文件
 npm init -y
 //1. 只能在英文的目录下成功运行   不能出现中文和空格
// 2.  npm install 命令安装包的时候,npm 包管理工具会自动把包的名称和版本号,记录到package.json中。

##dependencies 节点

记录使用 npm install 命令安装了哪些包

##一次性安装所有的包

npm install 或 npm i

##卸载指定的包

npm uninstall 包的名称 

卸载完成之后 package.json 的 dependencies 中会自动移除掉

##devDependencies 节点

在项目开发阶段会用到 项目上线之后不会用到 就把包放到这个节点

##安装指定的包 并记录到 devDependencies 节点中

//简写
npm i 包名 -D
//完整写法
npm install 包名 --save-dev 

***解决下载包慢的问题

  1. 切换 npm 的下包的服务器地址

    # 查看当前的下包镜像源
    npm config get registry
    #将下包的镜像源切换为淘宝镜像
    npm config set registry=https://registry.npm.taobao.org/
    #检查镜像源是否下载成功
    npm config get registry 
    
  2. nrm

    快速查看和切换下包的镜像源

    #通过 npm 将 nrm 安装为全局可用的工具
    npm i nrm -g
    #查看所有可用的镜像源
    nrm ls
    #切换为 taobao 镜像
    nrm use taobao 
    
    • 解决nrm无法加载的问题

      在命令行输入命令Set-ExecutionPolicy RemoteSigned -Scope Process 即可解决

***包的分类

  1. 项目包

    • 开发依赖包:被记录到devDependencies 节点中的包,只在开发期间会用到
    • 运行依赖包:被记录到dependencies 节点中的包,在开发期间和项目上线之后都会用到
  2. 全局包

    工具类型的包才会全局安装

    #全局安装指定的包
    npm i 包名 -g
    #卸载全局安装的包
    npm uninstall 包名 -g 
    

## i5ting_toc

可以把md 文档转为 html 页面的小工具

#将  i5ting_toc 安装为全局包
npm install i5ting_toc -g
# 调用  i5ting_toc 实现 md 转 html 的功能
 i5ting_toc -f 要转换的 md 文件的路径 -o 

## 规范的包结构

  1. 包必须以单独的目录而存在
  2. 顶级目录必须包含 package.json 这个包管理配置文件
  3. package.json 中必须包含 name,version,main 这三个属性 分别代表 包的名字 版本号 包的入口

***express框架

快速的创建web网站服务器或API接口服务器

##监听GET请求

app.get('请求URL',function(req,res) {/*处理函数*/})

##监听POST请求

app.post('请求URL',function(req,res) {/*处理函数*/})

##内容响应给客户端

  • res.send(“要发送的内容”) 可以把处理好的内容,发送给客户端
const express = require('express')
const app = express()
app.get('/user', function(req, res) {
//    user/:aa  可以监听到user后所有变化的参数 
// 冒号后面的值不是固定的   但是冒号必须写
//可以后面跟多个动态参数 user/:id/:name
    res.send('要发送的内容')
        //可以传递对象
})
app.listen(80, () => {
    console.log('开启');
})

##访问 查询字符串形式 发送到服务器的参数

查询参数

  • req.query

    客户端使用 ?name=zs&age=20

    req.query.name req.query.age

##获取URL 的动态参数

路径参数

  • req.params 默认是一个空对象 里面存放着通过动态匹配到的参数值

##注意

  • 冒号后面的值不是固定的 但是冒号必须写
  • 可以后面跟多个动态参数 user/:id/:name

## 托管静态资源

  • express.static()——创建一个静态资源服务器
    //快速的对外提供静态资源
    app.use(express.static('指定文件夹的路径'))
    
  • 托管多个静态资源目录
    //只需要多次调用express.static  先调用谁就先显示谁
    app.use(express.static('指定文件夹的路径'))
    app.use(express.static('指定文件夹的路径')) 
    
  • 挂载路径前缀
    app.use('前缀地址路径 ',express.static('指定文件的路径'))
    

*** nodemon

监听项目文件的变动,当代码被修改后 nodemon 会自动帮我们重启项目

##安装

npm install -g nodemon

##使用

//传统方式
node app.js
//可以实现自动重启项目的效果
nodemon app.js 

***路由

就是映射关系

##Express 路由

  • 客户端的请求与服务器处理函数之间的映射关系
  • 组成:请求的类型 请求的URL地址 处理函数

##创建路由模块

//1. 导入 express
var express = require('express')
//2. 创建路由对象
var router = express.Router()
//3. 挂载获取用户列表的路由
router.get('/user/list',function(req,res){
   res.send('Get user list')
}) 
//4. 挂载添加用户的路由
router.post('/user/add',function(req,res){
   res.send('Add new user')
}) 
//5. 向外导出路由对象
module.exports = router 

##注册路由

//1. 导入路由模块
const userRouter = require('./router/user.js') 

//2. 使用 app.user() 注册路由模块
app.use(userRouter) 
// app.use() 函数的作用  就是来注册全局 中间件 

app.listen(8899,function() {
  console.log('http://127.0.0.1')
}) 

## 为路由模块添加前缀

//1. 导入路由模块
const userRouter = require('./router/user.js') 

//2. 使用 app.user() 注册路由模块,并添加统一的访问前缀 /api
app.use('/api',userRouter) 

**Express 中间件

特指业务流程的中间处理环节

作用:对请求进行预处理

##中间件的格式

中间件函数的形参列表中,必须包含 next 参数 (next是函数 所以要调用)

路由处理函数中只包含req和res

##next 函数的作用

next 函数是实现多个中间件连续调用的关键

##定义中间件函数

const express = require('express')
const app = express()

const mw = function(req,res,next) {
  console.log('最简单的中间件')
  //把流转关系,转交给下一个中间件或路由
  next()
}

app.listen(80,()=>{
  console.log('1')
}) 

##全局生效的中间件

通过调用 app.use(中间件函数),定义一个全局生效的中间件

const express = require('express')
const app = express()

const mw = function(req,res,next) {
  console.log('最简单的中间件')
  //把流转关系,转交给下一个中间件或路由
  next()
}
app.use(mw)

//挂载路由
app.get('/',function(req,res) {
  res.send('hello world')
})
app.listen(80,()=>{
  console.log('1')
}) 

##中间件的作用

共享同一份req 和 res

app.use((req,res,next)=>{
  req.newTime = 'time'
  next()
})

//挂载路由
app.get('/',function(req,res) {
  res.send('hello world' + req.newTime)
})

##局部生效的中间件

不使用 app.use() 定义的中间件

只针对某个路由产生作用

//定义中间件函数 mw1
const mw1 = function(req,res,next) {
  console.log('这是中间件函数')
  next()
}

//mw1 这个中间件只在‘当前路由中生效’,这种用法属于‘局部生效的中间件’
app.get('/',mw1,function(req,res) {
  res.send('hello world ')
}) 

##定义多个局部的中间件

 //两种方式完全是等价的   任选其一
app.get('/',mw1,mw2,(req,res)=> { res.send('hellow world')})
app.get('/',[mw1,mw2],(req,res)=> { res.send('hellow world')}) 

**中间件的注意

  • 必须在路由之前定义中间件
  • 客户端发送过来的请求 可以连续调用多个中间件进行处理
  • 执行完中间件的业务代码之后 不要忘记调用 next() 函数
  • 防止代码逻辑混乱 调用 next() 函数后不要写额外代码
  • 多个中间件之间 共享 req 和 res 对象

##错误级别中间件

必须有4个参数 前后顺序分别是(err,req,res,next)

//1. 定义一个路由
app.get('/',(req,res)=>{
//抛出一个自定义错误
  throw new Error('服务器内部发生了错误')
  res.send('hello world')
})

app.use(function(err,req,res,next) { //错误级别的中间件
  console.log('发生了错误',err.message)//打印错误消息
  res.send('Error'+ err.message)// 向客户端响应错误相关的内容
}) 

app.listen(80,function() {
  console.log('11')
}) 

注意:错误级别的中间件必须定义在所有路由之后

##内置中间件

  • express.static 快速托管静态资源的内置中间件
  • express.json 解析json 格式的请求体数据(4.16.0+)
  • express.urllencoded 解析 URL - encoded 格式的请求体数据(4.16.0+)
    //配置解析 application/json 格式数据的内置中间件
    app.use(express.json())
    //配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
    app.use(express.urlencoded({extended:false})) 
    

注意:

  1. 在服务器,可以使用 req.body 这个属性 ,来接受客户端发送过来的请求体数据
  2. 默认情况下,如果不配置解析表单数据的中间件 则 req.body 默认等于 undefined

##自定义中间件

  • 定义中间件

    app.use(function(req,res,next) {
      //中间业务逻辑
    })
    
  • 监听req的data事件

    数据量比较大,会把数据切割后,分批发送到服务器 data事件可能会触发多次

    //1. 定义变量  来存储客户端发送过来的请求数据
    let str = ''
    //2. 监听 req 对象的 data 事件(客户端发送过来的请求体数据)
    req.on('data',(chunk)=>{
    //拼接请求体数据  隐式转换为字符串
      str += chunk 
    })  
    
  • 监听req 的end事件

    //1. 定义变量  来存储客户端发送过来的请求数据
    let str = ''
    //2. 监听 req 对象的 data 事件(客户端发送过来的请求体数据)
    req.on('data',(chunk)=>{
    //拼接请求体数据  隐式转换为字符串
      str += chunk 
    }) 
    //3. 监听 req 的 end 事件
    req.on('end',()=>{
    //打印完整的请求体数据
      console.log(str)
      //把字符串格式的请求体数据  解析成对象格式
    }) 
    
  • 使用 querystring 模块解析请求体数据

    // 导入处理 querystring 的 Node.js 内置模块
    const qs = require('querystring')
    
     //4. 调用 qs.parse() 方法   把查询字符串解析为对象
    const body = qs.parse(str) 
    
  • 解析出来的数据挂载为 req.body

    req.on('end',()=>{
      const body = qs.parse(str)
      req.body = body
      next()
    })
    

**定义JSONP接口

##实现JSONP的接口步骤

const express = require('express')
const app = express()

app.get('/api/get', function(req, res) {
    // 1. 获取客户端发送过来的回调函数的名字
    const fnName = req.query.callback
        //2. 得到 JSONP 形式发送给客户端的数据
    const data = { name: 'zs', age: '22' }
        //3. 函数调用
        // const fn = `${fnName}(${JSON.stringify(data)})`
        // 响应给客户端的 script 标签进行解析  
        // res.send(fn)
    const jsonStr = JSON.stringify(data)
    res.send(fnName + '(' + jsonStr + ')')
     //本质就是函数的调用   数据是经过函数的参数来传递 
})
app.listen(80, () => {
    console.log('开启');
})

##CORS资源共享

  1. 发起的是一个get的跨域请求,为了能够让浏览器不拦截这项数据,服务端需要在响应头设置Access-Control-Allow-Orgin
  2. 发起的是get的跨域请求 并且在请求头中带上了自定义字段 ,服务端需要在响应头设置 Access-Control-Allow-Orgin Access-Control-Allow-Headers
  3. 发起的是一个put的跨域请求,为了能够让浏览器不拦截这项数据,服务端需要在响应头设置 Access-Control-Allow-Orgin Access-Control-Allow-Methods
  4. 发起的是一个put的跨域请求 并且携带了自定义请求头 服务端需要在响应头设置 Access-Control-Allow-Orgin Access-Control-Allow-Headers Access-Control-Allow-Methods

四、数据库

***数据库的基本使用

##创建数据库

  • 点击新建数据库按钮
  • 填写数据库的名称
  • 点击Apply 按钮,创建数据库

##创建数据表

  1. 数据类型
    • int整数
    • varchar(len)字符串
    • tinyint(1)布尔值
  2. 字段的特殊标识
    • PK 主键 唯一标识
    • NN 值不允许为空
    • UQ 值唯一
    • AI 值自动增长

**SQL

  • SQL语言只能在关系型数据库中使用

##SQL做的事情

对数据库的数据进行 增删改查

  1. 查询数据(select)
  2. 插入数据(insert into)
  3. 更新数据(update)
  4. 删除数据(delete)

##SELECT语句

SELECT 语句用于从表中查询数据

--从 FROM 指定的  【表中】 查询出 【所有的数据】  * 表示【所有的列】
SELECT * FROM 表名称
--从 FROM 指定的表中  查询指定列名称(字段) 的数据
SELECT 列名称 FROM 表名称 

注意:关键字对 大小写不敏感

##INSERT INTO 语句

INSERT INTO 语句用于向数据表中插入新的数据行

--列和值之间是一一对应 ,多个列和多个值之间,使用英文逗号分隔
--insert into 表名(列1,列2 ...) values(值1,值2 ...)
insert into users(username,password) values('tony stark','098123')

##UPDATE语句

Update 语句用于修改表中的数据。

--update 表名 set 列名称 = 新值 where 列名称=某值
--更新一个列
update users set password='88888888' where id=7 

--更新多个列
update users set password='admin123',status=1 where id=2

##DELETE语句

DELETE 语句用于删除表中的行

delete from 表名称 where 列名称=值

delete from users where id=1 

##where 子句

WHERE 子句用于 限定选择的标准

运算符:

  • <> 、 != 不等于
  • BETWEEN 在某和范围内
  • LIKE 搜索某种模式
--查询 username 不等于 admin的所有用户
SELECT * FROM users WHERE username<>'admin' 

##AND 和 OR运算符

  • AND 表示必须同时满足多个条件
  • OR 表示只要满足任意一个条件即可
--使用 and 来显示所有状态为0 且 id小于3 的用户
select * from users where status=0 and id<3
-- 使用 or 来显示所有状态为1 或者 username 为 zs 的用户
 select * from users where status=1 or username='zs'

##ORDER BY 子句

ORDER BY 语句用于根据指定的列对结果集进行排序(默认是升序 要想降序 加 desc)

--对 users 表中的数据  按照 status 字段进行 升序 排序
select * from users order by id asc
--  降序 
 select * from users order by id desc

##ORDER BY 子句 – 多重排序

-- 对 users 表中的数据  先按照status 字段进行降序排序,在按照 username 的字母顺序,进行升序排序(后面用逗号进行罗列就好了)
select * from users order by status desc,username asc 

##COUNT( *)函数

COUNT( *) 函数用于返回查询结果的总数据条数

select count(*) from 表名      --返回表中有多少条数据

select count(*) from users where status=0   
-- 返回的是符合条件的数据的个数 
  • 使用AS 为列设置别名
    --将列名称从 count(*) 修改为 total 
    select count(*) as total from users where status=0 
    

**操作mysql 数据库的步骤

  • 安装 操作 MySQL 数据库的第三方模块
  • 连接到MySQL 数据库(都需要账号密码)
  • 执行sql 语句
  1. 安装MySQL 模块

    npm install mysql
    
  2. 配置 MySQL 模块

    //1. 导入 MySQL 模块
    const mysql = require('mysql')
     // 2. 建立与 MySQL 数据库的连接
    const db = mysql.createPool({
      host:'127.0.0.1',//数据库的 IP 地址
      user:'root',     //登录数据库的账号
      password:'admin123',//登录数据库的密码
      database:'my_db_01'//指定要操作哪个数据库
    }) 
    
  3. 测试 mysql 模块能否正常工作

    调用 db.query() 函数

    //检测 MySQL 模块能否正常工作
    db.query('select 1',(err,results)=>{
      if(err) return console.log(err.message)
      //能打印说明数据库连接正常
      console.log(results)
    })
    

## 查询数据

//查询 users 表中所有的用户数据
const sqlStr = select * from users
db.query('sqlStr ',(err,results)=>{
//查询失败
  if(err) return console.log(err.message)
  //查询成功
  console.log(results)
}) 

##插入数据

判断 results.affectedRows ===1 说明插入成功

//要插入 users 的数据
const user = { username:'gg',password:'999999'}
//待执行的 sql 语句   ? 表示占位符
const sqlStr = 'insert into users (username,password) values(?,?)'
//使用数组 依次为 ? 占位符 指定具体的值
db.query(sqlStr,[user.username,user.password],(err,results) => {
  if(err) return console.log(err.message)//失败
  if(results.affectedRows === 1) {
    console.log('插入数据成功')//成功
  }
}) 
  • 插入数据便捷方式

    如果对象的 每一个属性 和 数据表的字段一一对应

    const sqlStr = 'insert into users  set ? ' 
    

##更新数据

//1. 要更新的数据对象
const user = {id:7,username:'aaa',password:'000'}
//2.要执行的 sql 语句
const sqlStr = 'update users set username=?,password=? where id=?'
//3. 调用 db.query() 执行 sql 语句的同时  使用数组依次为占位符指定具体的值
db.query(sqlStr,[user.username,user.password,user.id],(err,resullts)=>{
  if(results.affectedRows === 1) {
      console.log('插入数据成功')//成功
})
  • 更新数据的便捷方式
    const sqlStr = 'update users set ? where id=?'
    

##删除数据

const sqlStr = 'delete from users where id=?'
//如果 sql 语句中只有 一个占位符(也就是一个 ? )则可以省略数组
db.query(sqlStr,1,(err,results)=>{
  if(results.affectedRows === 1) {
      console.log('删除数据成功')//成功
})
  • 标记删除
    //使用 update 语句代替 delete 语句  只更新数据的状态  并没有真正的删除                                                                                                                                               
    

***前后端身份认证

状态保持

通过一定手段完成对用户身份的确认(手机验证码登录,邮箱登录 ,二维码登录)

##身份认证方式

  • 服务端渲染推荐使用Session 认证机制
  • 前后端分离推荐使用 JWT认证机制

##Session认证机制

  1. HTTP协议的无状态性

    每次的http 请求都是独立的,连续多个http 请求之间没有直接关系,服务器不会主动保留每次 http 请求的状态

  2. http无状态的突破

    cookie存储方式

    • 自动存储
    • 自动携带(不用在写js代码)
      使用方式
      res.cookie(‘userid’,user.id)

    userid:表示存储在cookie中的名称

    user.id:表示存储在cookie中的值

##cookie数据不具有安全性

不要使用 Cookie 存储重要且隐私的数据!比如用户的身份信息、密码等

##使用Session 认证

  1. 安装 express-session 中间件
npm install express-session

2. 配置express-session 中间件

//导入
const session = require('express-session')
//配置
app.use(session({
  secret:'',//secret 属性的值可以是任意字符串
  resave:false,//固定写法
  saveUninitialized:true//固定写法
})) 

3. 在session 中存数据(存储在服务器中)

当 express-session 中间件配置成功后,即可通过req.session 来访问和使用session 对象,存储用户的关键信息

4. 从 session 中取数据

req.session

5. 清空session

调用 req.session.destroy()函数

##JWT认证机制

  • 当前端请求后端接口 不存在跨域问题的时候 使用Session 身份认证机制
  • 跨域请求 推荐JWT 认证机制
  • 最流行的 跨域认证的解决方案

##JWT工作原理

用户的信息通过 Token 字符串的形式,保存客户端的浏览器,通过还原 Token 字符串的形式来认证用户身份

##JWT组成部分

  • Header 头部(保证token的安全性)
  • Payload 有效荷载(真正的用户信息)
  • Signature 签名(保证token的 安全性) ——>保证信息不会被篡改

***在 Express 中使用 JWT

如何在服务器生成 token的字符串

##安装 JWT 相关的包

npm install jsonwebtoken express-jwt
 // jsonwebtoken  生成 JWT 字符串
 // express-jwt   将JWT 字符串解析还原成 JSON 对像

##导入 包

##定义secret 密钥

保证JWT 字符串的安全性 (字符串的加密和解密)

//帮助我们生成第三部分的字符串(也就是Signature)
const secretKey = ‘xxx’ 

##生成JWT 字符串

jwt.sign({参数1},参数2,{参数3})
// 参数1 : 用户的信息对象
// 参数2 : 加密的密钥
// 参数3 : 配置对像 可以配置当前 token 的有效期{expiresIn:'30S'}  expiresIn 属性名固定

##将JWT 字符串还原为 JSON 对象

//注册转换为JSON对像中间件
//expressJWT({ secret: secretKey}) 用来解析 token 的中间件
//unless({ path:[/^\/api\//] })  指定哪些接口不需要访问权限
app.use(expressJWT({ seret: secreKey }).unless({ path:[/^\/api\//]})) 

***状态保持的三种方式

http的无状态性

  • Cookie

    自动存数据

    自动携带数据

  • Session

    本质上依赖 Cookie

    Session 的方案中,真实的是存储在服务器的,给浏览器的cookie 存的只是一个sid

  • Token

    Session 的局限性:

    cookie的数据,在跨域的情况下,不会自动携带

    Session会占用服务端的资源

    Token是由后端生成,由浏览器来存储

    手动的存—> LocalStorage

    手动的带到请求中

0

评论区