Node.js介绍
- 重要性:
Node.js在前端核心技术体系起到承上启下的作用 - Node.js能做服务端:小程序、App、网站、游戏
3.学习Node.js的十大模块
- 计算机基础
- Node.js ApI
- 包管理工具
- HTTP协议
- Express框架
- Mongodb数据库
- 会话控制
- API接口
- 实战案例
- 服务器部署
Node.js是什么
官网定义:Node.js是一个开源的,跨平台的JavaScript运行环境
通俗来说:Node.js就是一款应用程序,是一款软件,它可以运行JavaScript
Node.js的作用
- 开发服务器应用
- 开发工具类应用
webpackvitebabel - 开发桌面端应用
electronVScodeFigmaPostman
 //true
Buffer
什么是Buffer
Buffer缓冲区,是一个类似于Array的对象,用于表示固定长度的字节序列。换句话说,Buffer就是一段固定长度的内存空间,用于处理二进制数据
Buffer的特点
- Buffer大小固定且不能修改
- Buffer性能较好,可以直接对计算机内存进行操作
- 每个元素大小为1字节
创建Buffer
- Buffer.alloc
//创建了一个长度为 10 字节的 Buffer,相当于申请了 10 字节的内存空间,每个字节的值为 0
let buf_1 = Buffer.alloc(10); // 结果为
- Buffer.allocUnsafe
//创建了一个长度为 10 字节的 Buffer,buffer 中可能存在旧的数据, 可能会影响执行结果,所以叫 unsafe
let buf_2 = Buffer.allocUnsafe(10);
3.Buffer.from
//通过字符串创建
Buffer let buf_3 = Buffer.from('hello');
//通过数组创建 Buffer
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
Buffer操作与注意事项
1.Buffer与字符串的转化
我们可以借助toString方法将Buffer转为字符串
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117])
console.log(buf_4.toString())
toString 默认是按照 utf-8 编码方式进行转换的
Buffer的读写
Buffer 可以直接通过[] 的方式对数据进行处理。
//读取
console.log(buf_3[1]);
//修改
buf_3[1] = 97;
//查看字符串结果
console.log(buf_3.toString())
计算机的基本组成
fs模块
fs模块可以实现与硬盘的交互,例如文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的相关操作
文件写入
文件写入就是将数据保存到文件中,可以用下面一些方法
writeFile异步写入writeFileSync同步写入appendFile/appendFileSync追加写入createWriteStream流式写入
writeFile 异步写入
语法:fs.writeFile(file, data[, options], callback)
参数说明:
- file 文件名
- data 待写入的数据
- options 选项设置
- callback 写入回调
返回值: undefined
// require 是 Node.js 环境中的'全局'变量,用来导入模块
const fs = require('fs');
//将 『三人行,必有我师焉。』 写入到当前文件夹下的『座右铭.txt』文件中
fs.writeFile('./座右铭.txt', '三人行,必有我师焉。', err => {
//如果写入失败,则回调函数调用时,会传入错误对象,如写入成功,会传入 null
if (err) {
console.log(err);
return;
}
console.log('写入成功')
})
writeFileSync 同步写入
语法: fs.writeFileSync(file, data[, options])
参数:与fs.writeFile 大体一致,只是没有 callback 参数
返回值: undefined
// require 是 Node.js 环境中的'全局'变量,用来导入模块
const fs = require('fs');
//将 『三人行,必有我师焉。』 写入到当前文件夹下的『座右铭.txt』文件中
try {
fs.writeFileSync('./座右铭.txt', '三人行,必有我师焉。');
console.log('创建成功');
} catch (e) {
console.log(e);
}
console.log('fuck you');
Node.js 中的磁盘操作是由其他 线程完成的,结果的处理有两种模式:
同步处理 JavaScript 主线程 效率较低
异步处理 JavaScript 主线程 效率较好
文件追加写入
appendFile 作用是在文件尾部追加内容,appendFile 语法与 writeFile 语法完全相同
语法:
fs.appendFile(file, data[, options], callback)
fs.appendFileSync(file, data[, options])
返回值: 二者都为 undefined
const fs = require('fs')
fs.appendFile('./座右铭.txt', '择其善者而从之,其不善者而改之。', err => {
if (err) throw err;
console.log('追加成功')
});
fs.appendFileSync('./座右铭.txt', '\r\n温故而知新, 可以为师矣');
createWriteStream 流式写入
语法: fs.createWriteStream(path[, options])
参数说明:
- path 文件路径
- options 选项配置
返回值: Object
const fs = require('fs')
let ws = fs.createWriteStream('./观书有感.txt');
ws.write('半亩方塘一鉴开\r\n');
ws.write('天光云影共徘徊\r\n');
ws.write('问渠那得清如许\r\n');
ws.write('为有源头活水来\r\n');
ws.close()
程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。 流式写入方式适用于 大文件写入或者频繁写入的场景, writeFile 适合于 1-5 写入文件的场景 写入频率较低的场景
文件写入场景
下载文件安装软件保存程序日志,如果Git编辑器保存文件视频录制
当需求持久化保存数据的时候,应该想到文件写入
文件读取
文件读取就是通过程序从文件中拿到数据,可以使用如下几种方式
- readFile 异步读取
- readFileSync 同步读取
- createReadStream 流式读取
readFile 异步读取
语法:fs.readFile(path[, options], callback)
参数说明:
- path 文件路径
- options 配置项
- callback回调函数
返回值:undefined
const fs = require('fs')
fs.readFile('./座右铭.txt', (err, data) => {
if (err) throw err
console.log(data.toString());
})
readFileSync 同步读取
语法:fs.readFileSync(path[, options])
参数说明:
- path 文件路径
- options 配置项
返回值:Buffer或者String
let fileData = fs.readFileSync('./观书有感.txt')
console.log('fileData', fileData.toString());
let fileData1 = fs.readFileSync('./座右铭.txt', 'utf-8')
console.log('fileData1', fileData1);
createReadStream 文件的流式读取
什么是流式读取:把文件一块一块读
语法:fs.createReadStream(path[, options])
参数说明:
- path文件路径
- options 选项配置 返回值:Object
//创建读取流对象
let rs = fs.createReadStream('./观书有感.txt');
//每次取出 64k 数据后执行一次 data 回调
rs.on('data', data => {
console.log(data);
console.log(data.length);
});
//读取完毕后, 执行 end 回调
rs.on('end', () => {
console.log('读取完成')
})
读取文件的应用场景
- 编辑器打开文件
- 查看图片
- 播放视频
- 播放音乐
- Git查看日志
- 上传文件
- 查看聊天记录
文件复制
const fs = require('fs')
// 方式一:readFile
let fileData = fs.readFileSync('./嘻嘻嘻.mp4')
fs.writeFileSync('./嘻嘻嘻-2.mp4', fileData)
// 方式二:createReadStream (流式方式更好,所占资源更少)
let readStream = fs.createReadStream('./嘻嘻嘻.mp4')
let writeStream = fs.createWriteStream('./嘻嘻嘻-3.mp4')
readStream.on('data', chunk => {
writeStream.write(chunk)
})
//另一种快速写法
readStream.pipe(writeStream)
文件重命名和移动
在 Node.js 中,我们可以使用 rename 或 renameSync 来移动或重命名文件或文件夹
语法:
fs.rename(oldPath, newPath, callback)
fs.renameSync(oldPath, newPath)
const fs = require('fs')
fs.rename('./file.txt', './fileNew.txt', (err) => {
if (err) throw err
console.log('文件重命名成功')
})
fs.renameSync('./fileNew.txt', './fileDir/file.txt')
文件删除
在Node.js中,我们可以使用unlink或unlinkSync来删除文件
语法:
fs.unlink(path, callback)
fs.unlinkSync(path)
const fs = require('fs');
fs.unlink('./嘻嘻嘻.mp4', (err) => {
if (err) {
console.log(err);
} else {
console.log('删除成功');
}
});
fs.unlinkSync('./嘻嘻嘻-2.mp4')
14.4版本有个新方法rm与rmSync、
// rm rmSync方法 14.4版本新方法
fs.rm('./嘻嘻嘻-3.mp4', (err) => {
if (err) {
console.log(err);
} else {
console.log('删除成功');
}
});
文件夹操作
Node.js可以对文件夹进行创建 读取 删除等操作
mkdir/mkdirSync创建文件夹readdir/readdirSync读取文件夹rmdir/rmdirSync删除文件夹
mkdir创建文件夹
我们可以使用 mkdir 或 mkdirSync 来创建文件夹
语法:
fs.mkdir(path[, options], callback)
fs.mkdirSync(path[, options])
创建单个文件夹
const fs = require('fs')
// 单个文件夹创建
fs.mkdir('./Video', (err) => {
if (err) throw err
console.log('创建成功');
})
fs.mkdirSync('./Img')
递归创建文件夹
// 递归创建
fs.mkdir('./A/B/C', { recursive: true }, (err) => {
if (err) throw err
console.log('创建成功');
})
读取文件夹
在Node.js中,我们可以使用readdir或readdirSync来上实现读取文件夹
语法:
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
const fs = require('fs')
fs.readdir('./', (err, data) => {
if (err) throw err
console.log('data', data); //获取名称
})
const data = fs.readdirSync('./')
console.log('data', data); //readdirSync 返回值是一个数组
删除文件夹
可以使用rmdir或者rmdirSync来删除文件夹
语法:
fs.rmdir(path[, options], callback)
fs.rmdirSync(path[, options])
单个删除
const fs = require('fs')
fs.rmdir("./html", (err) => {
if (err) throw err
console.log('删除成功');
})
递归删除
const fs = require('fs')
//未来要被弃用了,建议用rm
fs.rmdir("./fileDir", { recursive: true }, (err) => {
if (err) throw err
console.log('删除成功');
})
// rm
fs.rm("./fileDir", { recursive: true }, (err) => {
if (err) throw err
console.log('删除成功');
})
查看资源状态
在Node.js中,我们可以使用stat或statSync来查看资源的详细信息
语法:
fs.stat(path[, options], callback)
fs.statSync(path[, options])
const fs = require('fs')
fs.stat('./fileDir/test.txt', (err, data) => {
if (err) throw err
console.log('data', data);
})
结果值对象结构:
- size 文件体积
- birthtime 创建时间
- mtime 最后修改时间
- isFile 检测是否为文件
- isDirectory 检测是否为文件夹
- ....
__dirname
__dirname是Node.js环境中的全局变量
__dirname保存着当前文件所在目录的绝对路径,可以与文件名拼接成绝对路径
使用 fs 模块的时候,尽量使用 __dirname 将路径转化为绝对路径,这样可以避免相对路径产生的 Bug
path模块
path模块提供了操作路径的功能,介绍几个常用的几个API:
- path.resolve 拼接规范的绝对路径
- path.sep 获取操作系统的路径分隔符
- path.parse 解析路径并返回对象
- path.basename 获取路径的基础名称
- path.dirname 获取路径的目录名
- path.extname 获取路径的扩展名
const path = require('path');
//获取路径分隔符
console.log(path.sep);
//拼接绝对路径
console.log(path.resolve(__dirname, 'test')); //用的很多
//解析路径
let pathname = 'D:/program file/nodejs/node.exe';
console.log(path.parse(pathname));
//获取路径基础名称
console.log(path.basename(pathname))
//获取路径的目录名
console.log(path.dirname(pathname));
//获取路径的扩展名
console.log(path.extname(pathname));
Http协议(非常重要)
什么是Http协议
HTTP(hypertext transport protocol)协议;中文叫超文本传输协议
这个协议详细规定了 浏览器 和万维网 服务器 之间互相通信的规则。
协议中主要规定了两个方面的内容:
- 客户端:用来向服务器发送数据,可以被称之为
请求报文 - 服务端:向客户端返回数据,可以被称之为
响应报文
报文:可以理解成就是一堆字符串
窥探Http报文
fiddler
fiddler是一个可以查看http报文的软件,可以理解为浏览器与服务器传输报文的中介。
请求报文结构
- 请求行
- 请求头
- 空格
- 请求体
请求行
常见的几种方法:
请求头
格式:『头名:头值』
常见的请求头有:
- Host 主机名
- Connection 连接的设置 keep-alive(保持连接);close(关闭连接)
- Cache-Control 缓存控制 max-age = 0 (没有缓存)
- Upgrade-Insecure-Requests 将网页中的http请求转化为https请求(很少用)老网站升级
- User-Agent 用户代理,客户端字符串标识,服务器可以通过这个标识来识别这个请求来自 哪个客户端 ,一般在PC端和手机端的区分
- Accept 设置浏览器接收的数据类型
- Accept-Encoding 设置接收的压缩方式
- AcceptLanguage 设置接收的语言 q=0.7为喜好系数,满分为1
- Cookie
Http的请求体
请求体内容的格式是非常灵活的
(可以是空)===>GET请求
(也可以是字符串,还可以是JSON)===>Post请求
例如:
- 字符串:keywords=手机&price=2000
- JSON:{"keywords":"手机","price":2000}
响应报文
- 响应行
Http/1.1 200 Ok
HTTP/1.1:HTTP协议版本号
200:响应状态码
OK:响应状态描述
响应状态码和响应字符串关系是一一对应的
- 响应头
- 空行
- 响应体
http模块
创建http服务
// 1.导入http模块
const http = require('http')
// 2.创建服务对象
// request,是对请求报文的封装对象,通过request对象可以获得请求报文的数据
// response,是对响应报文的封装对象,通过response对象可以设置响应报文的数据
const server = http.createServer((request, response) => {
response.end('hello server')
})
// 3.监听端口,启动服务
server.listen(8080, () => {
console.log('服务已经启动,端口8080正在监听中...')
})
http.createServer里的回调函数的执行时机: 当接收到 HTTP 请求的时候,就会执行
http服务的注意事项
1.响应内容中文乱码的解决办法
response.setHeader('content-type','text/html;charset=utf-8');
获取http请求报文
想要获取请求的数据,需要通过request对象
- 请求方法
request.method - 请求版本
request.httpVersion - 请求路径
request.url - URL路径
require('url').parse(request.url).pathname - URL查询字符串
require('url').parse(request.url,true).query - 请求头
request.headers - 请求体
request.on('data',function(chunk){}) request.on('end',function{})
获取请求体
模拟请求过程
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模拟请求</title>
</head>
<body>
<form action="http://localhost:8080" method="post">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
index.js
const http = require('http')
const server = http.createServer((request, response) => {
let body = ''
// 绑定data事件
request.on('data', chunk => {
body += chunk
})
// 绑定end事件
request.on('end', () => {
console.log(body) //会有请求体数据
// 响应
response.end('hello world')
})
})
server.listen(8080, () => {
console.log('服务已经启动,端口8080正在监听中...')
})
获取请求路径与查询字符串
旧版
const http = require('http')
// 导入url模块
const url = require('url') //url也是Node.js的一个内置模块,专门用来解析url的
const server = http.createServer((request, response) => {
// 解析request.url
let res = url.parse(request.url, true)
console.log('res', res);
// 路径
let pathname = res.pathname
console.log('pathname', pathname);
// 查询字符串
let keyword = res.query.keyword
console.log('查询的关键字', keyword);
response.end('url')
})
server.listen(8080, () => {
console.log('服务已经启动,端口8080正在监听中...')
})
新版本(建议)
const http = require('http')
const server = http.createServer((request, response) => {
console.log('request.url', request.url);
// 实例化URL对象
let url = new URL(request.url, 'http://localhost:8080')
// 输出路径
console.log('路径名称', url);
// 输出查询字符串
console.log('查询字符串', url.searchParams.get('keyword'));
response.end('url new')
})
server.listen(8080, () => {
console.log('服务已经启动,端口8080正在监听中...')
})
http请求练习
//1、引入http模块
const http = require("http");
//2、建立服务
const server = http.createServer((request, response) => {
let { url, method } = request; //对象的解构赋值
//设置响应头信息
//解决中文乱码
response.setHeader("Content-Type", "text/html;charset=utf-8")
if (url == "/register" && method == "GET") {
response.end("注册页面");
} else if (url == "/login" && method == "GET") {
response.end("登录页面");
} else {
response.end("<h1>404 Not Found</h1>")
}
})
//3、监听端口
server.listen(8000, () => {
console.log('服务启动中....');
})
//1、引入http模块
const http = require("http");
//2、建立服务
const server = http.createServer((request, response) => {
let { url, method } = request; //对象的解构赋值
//设置响应头信息
//解决中文乱码
response.setHeader("Content-Type", "text/html;charset=utf-8")
if (url == "/register" && method == "GET") {
response.end("注册页面");
} else if (url == "/login" && method == "GET") {
response.end("登录页面");
} else {
response.end("<h1>404 Not Found</h1>")
}
})
//3、监听端口
server.listen(8000, () => {
console.log('服务启动中....');
})
设置http响应报文
- 设置响应状态码
response.statusCode - 设置响应状态描述
response.statusMessage用的非常少 - 设置响应头信息
response.setHeader('头名','头值') - 设置响应体
response.write('xx')response.end('xx')
write 和 end 的两种使用情况:
//1. write 和 end 的结合使用 响应体相对分散
response.write('xx');
response.write('xx');
response.write('xx');
response.end(); //每一个请求,在处理的时候必须要执行 end 方法
//2. 单独使用 end 方法 响应体相对集中
response.end('xxx');
网络资源加载基本过程
网页资源的加载都是循序渐进的,首先获取 HTML 的内容, 然后解析 HTML 再发送其他资源的请求,如 CSS,Javascript,图片等。 理解了这个内容对于后续的学习与成长有非常大的帮助
设置mime类型
mime类型(媒体类型)是一种标准,用来表示文档、文件或者字节流的性质和格式。
mime 类型结构:[type]/[subType]
Http服务可以设置响应头Content-Type来表明响应体的mime类型,浏览器会根据该类型决定如何处理资源
下面是常见文件对应的 mime 类型:
html: 'text/html',
css: 'text/css',
js: 'text/javascript',
png: 'image/png',
jpg: 'image/jpeg',
gif: 'image/gif',
mp4: 'video/mp4',
mp3: 'audio/mpeg',
json: 'application/json'
对于未知的资源类型,可以选择 application/octet-stream 类型,浏览器在遇到该类型的响应 时,会对响应体内容进行独立存储,也就是我们常见的 下载 效果
get和post请求的区别
- GET主要用来获取数据,Post主要用来提交数据
- GET带参数请求是将参数放到URL之后,Post是将参数放到请求体中
- Post请求相对GET安全一些,因为get会把参数暴露在地址栏
- GET请求大小有限制,一般为2k,而Post请求则没有大小限制