Node.js
什么是node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时。
什么是浏览器引擎
浏览器引擎是用于解析翻译和渲染页面的工具,主要用于解释翻译html css js
浏览器引擎分为两个:
渲染引擎:用于解释翻译和运行 html + css (通常指的浏览器引擎就是指的渲染引擎)
js 引擎:浏览器用于编译运行 js 的工具
核心模块
模块的概念,当讲到引入第三方模块的时候,再进行深入学习。
简单理解模块的概念:一个封装好的软件包,开箱即用。
fs文件系统模块
node.js中的文件系统,是一个工具,用于在操纵系统上对文件和目录进行操作,基本操作如:创建文件夹,删除文件,读取文件,写入文件等
fs.readFile
读文件
fs.writeFile
写文件
fs.readFileSync
同步读文件
fs.writeFileSync
同步写文件
fs.stat
读取文件状态
fs.readdir
读取目录
fs.mkdir
创建目录
fs.rmdir
删除目录
fs.unlink
删除文件
fs.access
查看路径是否存在
os模块
(operating system)操作系统模块
os.cpu
查看cpu信息
os.arch
查看cpu架构信息
os.platform
平台信息
path 路径模块
path.dirname
目录名称
path.basename
文件全称
path.extname
拓展名
path.join
结合路径
join 函数,用于拼接文件路径,通常用来得到一个绝对路径
assert 断言
当断言的内容为真时,什么都不会发生
当断言失败时,会抛出一个 AssertionError 的异常并显示第二个参数的消息
断言多用于检测参数
assert(sex === 'female', '性别不是女的')
cluster 集群模块
集群的含义就是一个事物的多个重复个体形成的群落,例如:蚂蚁,蜜蜂形成的蚂蚁群,蜜蜂群就是集群;
多台服务器可以组成服务器主机集群;
多个相同的应用程序也能组成应用程序集群,例如服务器应用集群,数据库集群等
node.js 的集群模块就是创建应用集群用的
集群的作用:集群模块可以让js代码在多个cpu核心上运行多个副本 可以更好的利用cpu,同时执行多份代码
集群中有主从的概念
// 判断是否是主程序
if (cluster.isMaster) {
for (let i = 0; i < os.cpus().length; i++) {
// 每个cpu核心上开启一个从程序
cluster.fork()
}
} else {
console.log(process.pid, '从程序中执行的代码')
}
Promise
promise中文意思是承诺,承诺一定在做完promise自己的事后,然后再做后面的事情
promise的作用
promise工具让异步调用看上去像同步一样,减少开发者在异步开发时的负担,少出异步错误。
Promise 的基本语法
Promise 里面的回调函数,将在promise对象实例化完成后被调用
const promise = new Promise((resolve, reject) => {
// 此回调函数就是promise承诺要完成的事情
// resolve: 当promise对象正确的处理完自己的事情时,一定要调用 resolve()
// reject: 本意是驳回,在此处代表promise承诺的事情,我不干了
// resolve 和 reject 在 promise内部 必须从中选择一个进行调用,不要同时调用
setTimeout(() => {
console.log('a')
// 完成promise承诺的事情后
// 调用 resolve
resolve('resolve的参数')
// 此处调用reject 代表promise 不干了
// reject 的参数就是 不干了的理由
// 通常来说这个参数是个异常对象
}, 1000)
});
then
: 代表然后,当promise内部执行resolve的时候就会执行 then 中的回调函数
catch
: 代表捕获异常,当promise内发生异常,或promise调用了reject,就会执行catch中的回调函数
finally
: 代表不管promise的承诺是否兑现,都会执行finally中的代码
服务器
ip
: 计算机在网络中的地址 其中本机地址为 127.0.0.1
一般情况可以使用 localhost 代表 127.0.0.1,若不成功则可以修改 C:\Windows\System32\drivers\etc\hosts 来定义 localhost
端口号
: 一个应用程序与互联网连接通信的出入口
协议: 例如 http https 都是协议名,规定网络通信如何进行
http
协议默认端口: 80
https
协议默认端口: 443
创建http服务器
// 引入网络通信模块
const http = require('http');
// 创建一个服务器对象
const app = http.createServer()
// 声明端口号
const port = 1024
req
: 请求对象,客户端发送来的数据封装到该对象中
res
: 响应对象,服务器用于做出回应的对象
// 绑定request事件
app.on('request', (req, res)=>{
// 服务器向客户端写数据
res.write('hello\n')
// 结束响应并传递数据
res.end('world')
})
// 启动服务器
app.listen(port, () => {
// 当服务器启动成功后,就会调用此函数
console.log(`server start: http://127.0.0.1:${port}`)
})
重定向
app.on('request', async (req, res) => {
if (req.url === '/') {
// 重定向
// 添加重定向的状态码
res.statusCode = '302'
// 添加重定向的路径
res.setHeader('Location', '/1.png')
res.end()
} else if (req.url === '/1.png') {
const data = await fsp.readFile(path.join(__dirname, 'public', '1.png'))
res.end(data)
} else {
res.end('404')
}
})
静态资源服务器
什么是静态资源?
不会发生变化的资源就是静态资源,静态资源一般指不会变化的文件
staticDirPath
定义静态资源文件夹
mongodb数据库
mongodb
是一个NoSql高性能分布式文档型数据库
拆解分析:
NoSql:非关系型查询语句(相对应的,Sql:结构化查询语句)
高性能:查询速度飞快
分布式:集群,并且有多种存储模式
切片:集群里每台数据库,负责存储部分数据,具体怎么存的只有mongo知道,但它能负责查询出来。
主从:集群里每台数据库有相同的数据,根据mongo定制的一套负载均衡逻辑,智能选择用哪个数据库。
基础命令
db.user.insertOne
单个插入
db.game.insertMany
批量插入
db.game.deleteOne
单个删除
db.game.deleteMany
批量删除
db.game.update
修改
db.game.save
保存
db.game.count
查询数据量
查询器
db.game.find
查找
$eq
: 匹配相等记录
$gt
: 匹配大于的记录
$gte
:匹配大于等于的记录
$in
:匹配指定范围中的记录
$lt
:匹配小于的记录
$lte
:匹配小于等于的记录
$ne
:匹配不等于指定值的记录
$nin
:匹配不在范围中的记录
聚合函数
聚合函数用于统计,将多条数据聚合成少量数据
官网:https://www.mongodb.com/docs/v6.0/reference/operator/aggregation/group/
db.games.aggregate([
// $match 用来过滤数据
{ $match: { price: { $gt: 300 } } },
// 数组中每个对象是一个聚合的条件
// 其中 $group 必填
// _id: 代表用什么字段进行分组,可以写 null 代表不分组
// $avg: 是内置的命令,用来求字段的平均值
{ $group: { _id: "$platform", avgPrice: { $avg: "$price" } } },
// $count 用于统计数量
// { $count: 'total' },
{ $sort: { avgPrice: -1 } }
], { explain: true }) // explain: 显示本次聚合查询的信息
mongoose连接数据库
官网:https://mongoosejs.com/
mongoose 是 mongodb 的 node.js 的数据库驱动
连接数据库
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test2', { useNewUrlParser: true })
const db = mongoose.connection; // 获取数据库连接对象
db.on('error', console.error.bind(console, 'connection error:')); // 绑定连接错误事件
db.once('open', function () { // 绑定一次打开数据库连接事件
// we're connected!
console.log("we're connected!")
})
mongodb://localhost:27017/test2
是连接字串
localhost
是数据库地址,可以换成对应的ip地址
27017
是数据库端口
test2
是数据库库名
也可以追加登录数据库的用户名和密码,如:mongodb://admin:111111@localhost:27017/test2
admin
: 账号 111111
: 密码
创建集合结构
结构schema就是用来描述数据库集合有哪些字段和各个字段的详细描述
const schema = new Schema({
// type: 该字段的数据类型
// index: 是否添加索引,添加了索引的字段查询速度更快
name: {type: String, index: true},
platform: {type: String, index: true},
price: {type: Number, index: true}
});
// 构造集合类型
const Game = model('game', schema)
express
Express 是一个快速,简单,极简的Node.js Web框架
HTTP协议
http(Hypertext transfer protocol)全称 超文本传输协议
分析理解:
超文本:比文本更多的信息(图片,超链接,媒体资源等等)
传输:运送
协议:服务端客户端共同认可的规则
常用请求头和响应头
请求头就是浏览器上的 request header
响应头就是浏览器上的 response header
Request Method
:请求方法
get
传递参数在url上可见 通过url.parse(req.url).query
取值
post
传递参数在url上不可见 通过req.body
取值
Content-Type
:内容类型
有常见的以下几种类型:
text/html
html文档
text/plain
纯文本
image/jpeg
.jpg图片
image/png
.png图片
text/xml
xml文档
application/json
json数据
application/x-www-form-urlencoded
表单url编码数据,例如:a=1&b=2&c=3
multipart/form-data
上传文件时常看到
charset=utf-8
指定编码集
Status Code
:状态码
状态码只指示请求或响应状态,不对业务负责
常见状态码:
200
请求成功
302
资源重定向
304
资源未改变,使用浏览器缓存
400
客户端请求的语法错误,服务器无法理解
403
权限不足 限制访问
404
资源未找到
500
服务器内部错误
503
请求超时
User-Agent
访问代理
意思是什么东西访问了服务器,通常可以用作平台判断。例如:不同浏览器,该值不一样
TCP_IP协议
TCP(translate controll protocol)传输控制协议
TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议
TCP/IP 主要规定链路层、网络层、传输层、应用层
网络层规定了ip地址
传输层规定了端口号 port
搭建服务器
const express = require('express'); // 引入 express 模块
const app = express(); // 创建服务器应用程序对象
const port = 80
注册接口
接口: 网络接口,一个 url 路径,对应服务器上一个提供服务的功能,这个功能就是服务器上的一个接口
第一个参数: url
第二个参数: 接口回调
app.get('/greeting', (req, res) => {
res.end('hello world')
})
启动服务器
app.listen(port, () => {
console.log(`server start on: http://127.0.0.1`)
})
在get里面重定向
res.redirect('/hello')
express.static
声明一个静态资源文件夹的路径
第一个参数: 访问静态资源时 url 前缀(含义是: 将 /static 路径 映射到 public 文件夹)
app.use('/static', express.static(path.join(__dirname, 'public')))
ajax异步请求
ajax (async javascript and xml)
翻译过来就是:异步js和xml
通常我们把 ajax 理解成:异步的网络请求
发起 ajax 请求的工具 我们称为 Http Client(http客户端)
使用浏览器自带的 ajax
XMLHttpRequest
// 创建 xhr
const xhr = new XMLHttpRequest()
// 打开连接
// xhr.open(requestMethod, url, async)
// requestMethod 请求方法 get 或 post
// url 请求地址
// async 是否异步 默认为 true,若为 false 则,xhr.send 在收到服务器响应后才会返回
xhr.open('post', '/play', true)
// 监听收到服务器响应事件
xhr.addEventListener('load', ev=>{
ev.currentTarget // 该对象中可以获取服务器响应数据
})
// 发送请求
xhr.send()
使用fetch发送ajax请求
// fetch api: https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch#%E6%94%AF%E6%8C%81%E7%9A%84%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0
// fetch 是一个 promise 函数
// fetch(url, options)
// url 请求路径
// options 配置对象
fetch(`/doGet?name=${fd.get('name')}&age=${fd.get('age')}`, {
method: 'GET', // 请求方法 *GET, POST, PUT, DELETE, etc.
mode: 'same-origin', // 跨域策略 no-cors(不跨域), *cors(跨域), same-origin(同源)
// referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
// body: JSON.stringify(data) // 数据体 body data type must match "Content-Type" header
}).then(res => {
// res 服务器的响应对象
console.log(res)
// res.text() 用字符串格式读取服务器返回的结果
// 该函数返回的是 promise
// return res.text()
return res.json()
// res.json() 用json对象读取返回值
// res.blob() 用blob对象(二进制数据对象)读取返回值
}).then(text => {
console.log(text)
})
解析post请求的参数
// 用来解析数据类型为 application/json 格式的数据
app.use(express.json())
// 用来解析数据类型为 application/x-www-form-urlencoded 格式的数据
app.use(express.urlencoded({extended: true}))
// 解析文件参数的配置
app.use(fileUpload({
// 文件大小限制
limits: {fileSize: 10 * 1024 * 1024},
// 使用临时文件
useTempFiles: true,
// 临时文件夹路径
tempFileDir: path.join(__dirname, 'tmp'),
// 解决中文乱码的字符集参数
defParamCharset: 'utf8'
}))
cookie
浏览器用于存储指定url请求下的参数的工具,就是cookie,是浏览器的状态管理工具
作用:
存储指定url路径下的参数,以 { key: value } 键值对的形式存储
设置数据失效时间,时间到后会自动失效
每次浏览器发起请求时,如果请求地址保存有cookie,那么浏览器会自动将cookie的值传给服务器 总的来说,cookie就是浏览器用来储存本地数据的
安装cookie工具
npm install cookie-parser
配置
const express = require('express')
const cookieParser = require('cookie-parser')
const app = express()
app.use(cookieParser())
cookie的读写
app.get('/', (req, res) => {
// 读取cookie
console.log(req.cookies)
// 写入cookie
// httpOnly: 只能在http协议中使用
// maxAge: 有效时间
res.cookie('a', '123', {httpOnly: true, maxAge: 3000})
res.end('hello world')
})
session
session是客户端链接服务器的一个会话,当创建与服务器的链接时,session由服务器创建,用于描述服务器状态的对象、用于多次请求之间能够共享数据
安装session工具
npm i express-session
session配置
const express = require('express')
const session = require('express-session')
const app = express()
const port = 1024
// 配置session
app.use(session({
secret: 'this is a secret key', // 必要参数 这是一个签名密钥
cookie: ('name', 'value', {})
// cookie: ('name', 'value', {maxAge: 5*60*1000, secure: false})
}))
session操作
app.get('/', (req, res) => {
// 读取session
console.log(req.session)
// 写入session
if (req.session.count)
req.session.count = req.session.count + 1
else
req.session.count = 1
res.end('hello world')
})
session的特点
session对象, 浏览器关闭之后,session对象消失。
session,默认情况下,30分钟,都不再和服务器端有交互,则session无效。
session可以实现服务器端数据的共享(临时数据)
session保存的数据在服务器内存中
更换客户端,session就找不到了
由于session是存在内存中,多台服务器的项目就不能有效访问session
中间件
中间件middleware,是一个采用责任链模式夹杂在我们的服务器方法中间的方法。
作用:在访问指定接口之前或之后的一个自定义方法,就是中间件
语法:
app.use((req, res, next)=>{
// 中间件逻辑
next()
})
// 或
router.use((req, res, next)=>{
// 中间件逻辑
next(someParams)
})
方法签名最后一个参数一定是 next
,且调用next就执行下一个方法,否则就需要在此处res.end
否则程序会挂起
next
方法调用时,可以接受一个Error
对象作为参数,用作抛出异常,任何异常将在下一个中间件的第一个参数中获得,接下来的异常处理就会用到
异常处理
异常处理在实际项目中非常常见,因为通常程序除了异常,服务器都需要一个统一的返回数据让页面显示,为了更友好,更好看,且数据格式需要在异常处理的时候格式化成需要的数据格式。
异常处理的方式就是使用中间件,中间件的位置需要在所有请求和中间件之后书写。如:
app.use((req, res, next)=>{
console.log('this is middleware')
next()
})
app.get('/', (req, res, next) => {
// 接口内也能接收一个 next
// next 函数用于接口抛出异常给后续中间件
// console.log('this is /')
// res.end('hello home!')
next(new Error('my error'))
})
// 定义异常处理器
app.use((err, req, res, next)=>{
console.log(err)
res.status(500)
res.end(err.stack)
})
异常处理器的方法签名中,第一个参数,始终是error,如果程序没有抛错的话,那么错误处理程序将不会被调用
可以安装 express-async-handler
包来代替异步处理器
跨域处理
当客户端请求的url域和服务器所在的域不同时,会触发浏览器的安全机制,限制跨域访问,此时服务器需要打开跨域访问的许可,允许跨域。在express中,需要在服务器启动前,安装如下代码:
// 设置允许跨域访问该服务.
app.all('*', function (req, res, next) {
// 设置允许跨域的响应头
res.header('Access-Control-Allow-Origin', '*');
// Access-Control-Allow-Headers ,可根据浏览器的F12查看,把对应的粘贴在这里就行
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', '*');
// res.header('Content-Type', 'application/json;charset=utf-8');
next();
})
跨域例子:例如:
服务器地址是:shampoo6.com,有一个接口 /game/info
另一个页面,地址是:cat.com/index.html
当 cat.com/index.html 页面访问 shampoo6.com/game/info 接口时,由于域名不同,这就产生了跨域
如果 shampoo6.com 服务器不做跨域处理,就会报如下错误:
Access to XMLHttpRequest at 'http://shampoo6.com/game/info' from origin 'cat.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
若不记得跨域响应头有哪些,可以使用 cors
包
安装cors包
npm i cors
const cors = require('cors')
const express = require('express')
const app = express()
// 跨域处理可以放在所有中间件的前面
app.use(cors())