node概念
Node实际上就是一个JacaScript运行环境 他集成了v8引擎,从而能对javascript代码进行解析执行
组成部分
v8 引擎 、内置API(eg:fs,path,http等模块
fs 文件系统模块
导入模块 const fs=require(‘fs’)
读文件:语法格式:fs.readFile(读取文件的路径,编码格式,function(err,results))传的参数表示失败获成功
写文件:语法格式:fs.writeFile(写入文件的路径,编码格式,回调函数)
注意:
- 内容是覆盖写入 文件夹不存在不会自动创建,会报错
- 只能创建文件,不能创建文件路径
path路径模块
- 用来处理路径
- 引入模块 const path = require(‘path’)
- path.join([…paths]) ,讲多个路径拼接在一起,这里的参数表示 可以传一个或多个路径片段
- path.basename(路径,[.ext]) 获取到路径中的文件名
不传入.ext 获取文件名后缀,传入ext 只获取文件名 - path.extname(路径) 获取路径中的文件扩展名
http模块
作用:用来创建web服务器
创建web服务器的步骤
- 导入 http模块
const http= require(‘http’) - 创建一个web服务器实例
调用http.createServer()方法 - 为服务器实例绑定result事件
通过 server.on(‘result’,回调函数) - 启动服务器
server.listen(3000,回调函数)
req对象和res对象
req请求对象包含请求相关信息 (请求方式,请求地址等)
res响应对象,包含响应相关信息
res.end(响应的内容)
解决相应中文乱码的问题,设置响应头:res.setHeader(‘Content-Type’,‘text/html;charset=utf-8’)
Node 模块化
概念 :将一个大文件拆分成多个独立并且相互依赖的小模块
好处 :1.提高代码的复用性
2. 提高代码的可维护性
3. 可以实现按需加载
模块化分类
- 内置模块 Node.js 官方提供的
- 自定义模块 用户创建的每个.js文件 一个js文件就是一个模块
- 第三方模块 第三方开发的模块
模块的加载
- 使用require()方法 加载需要的内置模块,用户自定义模块、第三方模块进行使用
- 使用require方法加载其他模块时,会执行被加载模块中的代码
- 在使用require加载用户自定义模块期间可以省略.js后缀名
- 使用require方法导入模块是,导入的结果永远以module.exports指向的对象为准
模块作用域
在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问 ,外部文件时访问不到的
模块成员
在模块中定义的变量,常量函数等都是模块的成员
对外共享模块成员
- 给module.exports 对象上面挂在属性
- 让module.exports 指向一个新对象
- 给exports对象上面挂在属性
包
安装包
npm install 包的名称(简写:npm i 包的名称)
npm i包的名称@版本 :安装指定包的版本
卸载包
npm uninstall 包的名称(简写 npm un 包的名称)
使用包的步骤
- 先安装包
- 导入包 require(‘包的名称’)
- 使用包
包管理配置文件(package.json)
- 初始化这个文件:npm init -y
- 注意每一个项目下面必须有一个包管理配置文件
- depencides节点 (记录的是项目开发和上线之后都需要用的包)
使用 npm i 包的名称|npm i 包的名称 --save(S)
- devdepencides 节点 (记录的是开发阶段用,项目上线之后不再使用的包)
使用npm i 包的名称 --dev (-D)
模块的加载机制
一. 优先从缓存中加载
二. 内置模块的加载优先级:内置模块的加载优先级最高
三. 自定义模块的加载机制
1. 加载自定义模块 ,如果没有指定“./”或“…/”开头的路劲标识符,则node会当作内置模块或是第三方模块进行加载
2. 加载自定义模块省略扩展名的加载顺序:确切的文件名>js扩展名>json扩展名>node扩展名>加载失败,终端报错>
四. 第三方模块的加载机制
1.先从当前模块的父目录开始,从/node_modules文件中加载第三方模块
2.如果没有找到对应的第三方模块,则移动到上一层父目录中,进行加载,知道文件系统的根目录,如果还没有就会报错
五. 目录作为模块
1. 在被加载的目录下查找一个交package.json的文件,并学着main属性,作为require()加载的入口
2. 如果目录没有package.json文件或者main入口不存在或无法解析,则Node.js将会试图加载目录下的Index.js文件
3. 如果以上两步都失败了,则Node.js会在中断打印错误消息,报告模块的缺失:Error :cannot find module xxx
express框架
一、创建web服务器
- 导入包
const express=require('express')
- 创建服务器
const app= express()
- 启动服务器
app.listen('8081',()=>{
console.log(`server is running at http://localhost:8081`)
})
二、监听get 和post 请求
- app.get(请求的url地址,请求对应的处理函数)
- app.post(请求的url地址,请求对应的处理函数)
三、获取查询参数
req.query 获取到的是对象
四、获取动态参数
req.params 获取到的是对象
五、托管静态资源
app.use(express.static(‘文件夹’))
express路由
概念:客户端请求和服务器处理函数之间的映射关系
定义路由的语法:app.get(url地址,请求处理函数)
app.post(url地址,请求处理函数)
路由的匹配:按照定义的先后顺序进行匹配;请求类型和请求的URL同时匹配成功,才会调用对应的处理函数
路由模块化
一、定义路由
- 引入express
const express=require('express')
- 创建路由对象
const router=express.Router()
- 挂在路由
router.get('/user/list',(req,res)=>{
res.send('get user list')
})
router.post('/login',(req,res)=>{
res.send('post login')
})
- 导出路由
module.exports=router
二、注册路由
1.导出路由
const router=require(' 路径 ')
2.注册路由
app.use('/api',router)
express中间件
一、概念
业务流程的中间处理环节是对请求的预处理
二、中间件语法格式
- 定义中间件
const kw = function(req,res,next){
console.log('中间件被触发了')
//一定要加next 否则就无法执行下面的路由
next()
}
三、全局中间件
app.use((req,res,next)=>{
next()
})
每个请求都会经过这个中间件
四、局部中间件
//定义中间件
const kw=function(req,res,next){
consloe.log('中间件被触发了')
}
//挂载路由
app.get('/user',kw,(req,res)=>{
res.send('get user)
})
只有某个请求才经过中间件
定义在路由处理函数的前面
注意事项:
1.一定要在路由之前注册中间件
2.客户端发送过来的请求,可以连续调用多个中间件进行处理
3.执行完中间件的业务代码之后,不要忘记调用next()函数
4.为了防止代码逻辑混乱,调用next()函数后不要额外的代码
5.连续调用多个中间件行,多个中间件之间,共享req和res对象
五、中间件分类
- 应用级别的中间件 绑定到app实例上的中间件
- 路由级别的中间件 绑定到router实例上的中间件
- 错误级别的中间件
作用: 用来捕获整个项目中发生的异常,从而防止项目崩溃
格式: function(err,req,res,next){
}
注意: 错误级别的中间件,必须要注册到所有路由器之后
- express内置的中间件
//通过express.json()中间件,解析表单中的JSON格式的数据
app.use(express.json())
//通过express.urlencoded()中间件,会解析表单中x-www-form-urlendcoded格式的数据
app.use(express.urlencoded({extended:false}))
//express.static()中间件
- 第三方中间件
express编写接口
导入express
const express=require('express')
创建服务器实例
const app =express()
配置解析表单的数据
app.use(express.urlencoded({extended:false}))
导入并注册路由
const router=require('路径')
app.use('/api',router)
启动服务器
app.listen(3000,()=>{
console.log('http://localhost:3000')
})
跨域解决方案
一、cors
概念:由一系列http响应头组成,http响应头决定浏览器是否阻止js代码跨域获取资源
实现原理:服务器端设置响应头
响应头字段
Access-Control-Allow-Origin字段
语法: Access-Control-Allow-Origin:<origin>|*
//origin参数的值指定了允许访问该资源的外域URL
//限制访问资源的书写方式
res.setHeader('Access-Control-Allow-Origin','www.baidu.com')
//允许访问任何资源的书写方式
res.setHeader('Access-Control-Allow-Origin','*')
Access-Control-Allow-Headers字段
//用来配置允许客户端向服务器发送额外的请求头信息
语法:
//允许客户端额外向服务器发送Content-Type请求头和X-Custom-Header请求头
//注意 多个请求头之间使用英文的逗号进行分割
res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header')
Access-Control-Allow-Methods字段
//默认情况下,cors仅支持客户端发起GET,POST,HEAD请求
//用来配置允许客户端以其他的请求方式向服务器请求资源
//只允许POST,GET,DELETE,HEAD请求方法
res.setHeader('Access-Control-Allow-Methods','POST,GET,DELETE,HEAD')
//允许所有的HTTP请求方法
res.setHeader('Access-Control-Allow-Methods','*')
请求分类
简单请求
条件(同时满足)
- 请求方式:GET,POST,HEAD三者之一
- http头部信息不超过一下几个字段
- 无自定义头部字段
- Accept
- Accptt-Language
- Content-Language
- DPR
- Downlink
- Save-Data
- Viewport-width
- width
- Content-Type(只有三个值application/x-www-form-urlencoded、multipart/form-data、text/palin)
特点:客户端和服务器之间只会发生一次请求
使用Mysql模块操作数据库
安装配置mysql模块
//导入mysql模块
const mysql=requeire('mysql')
//建立与mysql数据库的链接
const db=mysql.createPool({
host:'127.0.0.1', //数据库的ip地址
user:'root', //登录数据库的账号
password:'root',//登录数据库的密码
database:'my_db_01' //指定要操作那个数据库的名称
})
实现查询操作
const sql='select * from 数据库表名称'
实现插入操作
const sql='insert into 数据库表名称(username,password,status) values(?,?,?)'
插入便捷操作
const sql = 'insert into 数据库表名称 set ?'
实现更新操作
const user={
username:'erdan',
password:'123123'
}
const sql=`update 数据库表名称 set username=?,password=? where id=? `
ad.query(sql,[user.username,user.password,13],(err,results)=>{
if(err) return console.log(`sql语句执行失败:${err.message}`)
//判断更新是否成功
if(results.affectedRows===1) console.log('更新成功')
})
更新数据便捷操作
const user={
username:'xxxx',
password:'xxxx',
status:1
}
//将表中的id为10的数据更新成user的数据
const sql=`update 数据库表名称 set? where id=?`
db.query(sql,[user,10],(err,results)=>{
if(err) return console.log(`sql语句执行失败:${err.message}`)
//判断更新是否成功
if(results.affectedRows===1) console.log('更新成功')
})
实现删除操作
const sql= 'delete from 数据库的名称 where id=?'
db.query(sql,[user,10],(err,results)=>{
if(err) return console.log(`sql语句执行失败:${err.message}`)
//判断删除是否成功
if(results.affectedRows===1) console.log('删除成功')
})
标记删除操作
const sql = 'update 数据库表名称 set status=1 where id=?'
db.query(sql,10,(err,results)=>{
if(err) return console.log(`sql语句执行失败:${err.message}`)
//判断删除是否成功
if(results.affectedRows===1) console.log('删除成功')
})
身份认证
原因:http协议无状态
方式1.:服务端渲染推荐使用session做身份认证
方式2.:前后端分离的开发模式推荐使用jwt做身份认证
cookie
- 保存在浏览器当中
- 大小不超过4kb的字符串
- 可以设置过期时间expires
- 每个网站的cookie独立
- 请求自动携带cookie
- 不安全,可以伪造
session做身份认证
一、session的工作原理
- 当客户端发起登录请求,携带的账号和密码要先在服务器端做验证,如果账号密码正确,将用户信息保存在服务器内存中,会生成cookie,服务器将cookie相应给客户端,那么客户端会将cookie自动保存在浏览器中
- 当客户端再次发起请求,客户端会自动携带cookie,服务器获取到cookie进行认证,如果认证通过,服务器端将对应的信息响应给客户端
Node中使用session做身份认证- 下载安装express-session包
- 导入
- 进行配置,注册成中间件
- 在登录的接口中,登录成功保存用户信息
jwt做身份认证
工作原理
- 客户端去进行登录,服务器验证是否登录成功,如果成功,将用户的信息进行加密生成token字符串,响应给客户端
- 客户端将获取到的token保存在localStorage或者是sessionStorage
- 再次去发起请求,客户端要携带token 在请求投中设置一个Authorization:token
- 服务器将客户端发送过来的token进行解密,还原成用户对象
- 然后服务器进行比对,如果比对成功,就是身份认证通过,响应内容给客户端
Node实现jwt身份认证
1.下载安装jsonwebtoken (加密生成token字符串),express-jwt(将token字符串还原成用户信息对象)
2.导入包
const jwt=require('jsonwebtoken')
const {expressjwt}=require('express-jwt')
3.在登录的接口中,验证登录成功的化,就将用户的信息加密生成token字符串,响应给客户端
jwt.sign(用户信息对象,加密的密钥,配置对象)
4.解密token字符串
配置中间件 :app.use(expressjwt({secret:xxx,xxx}).unless(path[]))
- 通过req.auth获取用户的信息
- 项目会发生奔溃,使用错误级别的中间件解决
app.use((err,req,res,next)=>{
if(err.name==='UnauthorizedError'){
return res.send({
status:401,
message:'token失效'
})
}
res.send({
status:500,
message:'服务器内部发生了错误'
})
})
res.file在配置了multer之后使用的属性,获取上传文件的信息