写在最前:跟着视频学习只是为了在新手期快速入门。想要学习全面、进阶的知识,需要格外注重实战和
官方技术文档
,文档建议作为手册使用
系列文章
- 【Node.js】笔记整理 1 - 基础知识
- 【Node.js】笔记整理 2 - 常用模块
- 【Node.js】笔记整理 3 - npm
- 【Node.js】笔记整理 4 - node版本管理工具 nvm
- 【Node.js】笔记整理 5 - Express框架简单入门
- 【Node.js】笔记整理 6 - MongoDB
- 【Node.js】笔记整理 7 - mongoose
本文目录
- 系列文章
- [1、 fs ------ 文件模块](#1、 fs —— 文件模块)
-
- 文件写入
-
- [writeFile - 异步写入文件](#writeFile - 异步写入文件)
-
- [weiteFileSync - 同步写入文件](#weiteFileSync - 同步写入文件)
- [appendFile / appendFileSync ------ 追加写入](#appendFile / appendFileSync —— 追加写入)
- [createWriteStream - 流式写入](#createWriteStream - 流式写入)
- 读取文件
-
- [readFile - 异步读取](#readFile - 异步读取)
- [readFileSync - 同步读取](#readFileSync - 同步读取)
- [createReadStream - 流式读取](#createReadStream - 流式读取)
- fs模块实例
- [2、path ------ 路径模块](#2、path —— 路径模块)
-
- [path.resolve ------ 路径拼接](#path.resolve —— 路径拼接)
- [path.sep ------ 获取当前操作系统的路径分隔符](#path.sep —— 获取当前操作系统的路径分隔符)
- [path.parse ------ 解析路径](#path.parse —— 解析路径)
- 3、Http
- 模块化
1、 fs ------ 文件模块
fs模块提供了对文件、文件夹操作的能力。在这个模块中,写入的数据如果想要换行,需要使用\r\n
,而不是\n
另外请注意,读取到的都是Buffer
,你需要按照文件的格式选择对应的方法将其转化为需要的数据,比如读取txt文件,你可以使用toString()
进行转换
引入fs模块
js
const fs = require('fs')
文件写入
需要持久化保持数据时,除了直接存储在数据库,还有可以利用文件写入
writeFile - 异步写入文件
语法:fs.writeFile(file, data[, options], callback)
- file: 写入的文件名
- data: 写入文件的数据
- options: 写入时给文件的选项配置
- callback: 写入文件后的回调函数
示例:
js
const fs = require('fs')
fs.writeFile('./hello.js', 'console.log('hello node')', (res) => {
console.log(res)
// 写入失败则res 为 Error对象, 成功则为null
})
weiteFileSync - 同步写入文件
语法:fs.writeFileSync(file, data[, options])
, 注意没有回调函数
js
fs.writeFile('./hello.js', 'console.log('hello nodeSync')')
appendFile / appendFileSync ------ 追加写入
追加写入时在指定文件末尾添加内容
语法: fs.appendFile(file, data[, options], callback)
、fs.appendFileSync(file, data[, options])
二者返回undefined
createWriteStream - 流式写入
优势:可以减少打开关闭文件的次数 ,适合大文件写入 或者频繁写入 ,流式写入可以在这种场景下提高性能
语法: fs.createWriteStream(path[, options])
- path:文件路径
- options:选项配置
返回值:Object
使用流式写入时,需要先和文件建立通道: const ws = createWriteStream('filePath')
然后可以使用ws.wirte(data)
写入内容,文件内容写入完毕后,使用ws.close()
关闭通道,通道关闭前都可以向对应文件中写入数据
js
const ws = fs.createWriteStream('filePath')
// 流式写入数据
ws.write('hello world\r\n')
// 关闭通道
ws.close()
读取文件
当需要读外部文件获取信息时候都要进行文件读取,比如读音乐、读视频、读系统文件等等
readFile - 异步读取
语法:fs.readFile(path[, options], callback(err, data))
返回值:undefined
读取到的data是一个Buffer
,需要进行处理
js
const fs = require('fs')
fs.readFile('./hello.js', (err, data) => {
if(err){
// ...
}
// 读取到的是Buffer, 还需要转字符串
if(data){
data = data.toString()
}
})
readFileSync - 同步读取
语法: fs.readFileSync(path[, options])
返回值: Buffer
,读取结果
js
const fs = require('fs')
let data = fs.readFileSync('./hello.js')
const fileInfo = data.toString()
createReadStream - 流式读取
同样的你需要建立一个通道, 创建读取流对象: const rs = fs.createReadStream(path[, options], callback)
- 获取读取到的数据:
rs.on('data', (chunk) => {})
,绑定data
事件,chunk
是流式读取时每次读取到的Buffer
块,通过length
属性可以获取每个块的字节大小 - 读取完毕时可触发回调:
rs.on('end', () => {})
,绑定end
事件
fs模块实例
流式复制文件
非流式就是读完了然后写进一个新的,操作都简单就不用说了,这里主要记流式,边读边写。流式也是经常使用的方式,因为更适合读大文件的情景。并且对资源的利用更优
js
const rs = fs.createReadStream('./hello.js')
const ws = fs.createWriteStream('./hello_copy.js')
rs.on('data', chunk => {
ws.write(chunk)
})
rs.on('end', () => {
alert('文件复制完毕')
})
管道快速复制文件(不大的):
jsrs.pipe(ws)
文件重命名和移动
要用到fs
模块提供的rename()
API
语法:fs.rename(path, newPath, callback(err))
同步版本: fs.renameSync(path, newPath)
js
const fs = require('fs')
fs.rename('./hello.js', './newName.js', err => {
if(err){
//...
}else{
//...
}
})
通过上面的例子可以看到,这个API也可以用于移动文件
文件删除
要用到fs
模块提供的unlink
或unlinkSync
语法:unlink( path, callback(err) )
同步版类推
代码示例省略
node 14.4版本引入了新的删除文件API ------ rm
、rmSync
语法:fs.rm( path. callback(err) )
文件夹操作
API | 功能 |
---|---|
mkdir、mkdirSync | 创建文件夹 |
readdir、readdirSync | 读取文件夹 |
rmdir、rmdirSync (这两个api将来会被移除)、rm(建议使用) | 删除文件夹 |
1、创建文件夹
和linux命令名一样是mkdir
语法: fs.mkdir( path[, options], callback(err) )
js
const fs = requrie('fs')
fs.mkdir('./newFile.txt', err => {
// ...
})
// 递归创建
fs.mkdir('./a/b/c', { recursive: true }, err => {
// ...
}
2、文件夹读取
语法:fs.readdir( path, callback( err, data ) )
js
fs.readdier('./hello.js', (err, data) => {
if(err){
//...
}
// 处理读取结果data
})
3、删除文件夹
语法:fs.rm( path, callback(err) )
递归删除: fs.rm( path, { } )
js
fs.rm('./a', { recursive: true }, err => {
//...
})
查看文件资源状态
语法: fs.state( path, [, options], callback(err, data) )
、同步版本fs.stateSync
data结构:
- size: 文件体积
- birthtime:创建时间
- mtime:最后修改时间
- isFile:检测是否为文件
- isDirectory:检测是否为文件夹
会用到的全局变量:
__dirname
:可以获取其所在文件的所在目录的绝对路径,这可以避免工作目录变化的影响。__filename
:当前文件的绝对路径
2、path ------ 路径模块
常用API:
API | 功能 |
---|---|
path.resolve | 拼接规范的绝对路径 |
path.sep | 获取操作系统的路径分隔符 |
path.parse( filePath ) | 解析路径并返回对象 |
path.basename( filePath ) | 获取路径的基础名称 |
path.dirname( filePath ) | 获取路径的目录名 |
path.extname( filePath ) | 获取路径的扩展名 |
path.resolve ------ 路径拼接
语法: path.resolve( 绝对路径, 相对路径 )
js
const path = require('path')
let filePath = path.resolve(__dirname, './hello.js')
let filePath = path.resolve(__dirname, 'hello.js') // 不写./也可以
path.sep ------ 获取当前操作系统的路径分隔符
语法: path.sep
区别: window下返回值是\
,Linux下结果是/
path.parse ------ 解析路径
语法: path.parse( filePath )
返回值是一个Object:
- root:根
- dir:文件夹路径
- base:文件
- ext:文件类型
- name:文件名
3、Http
Http报文相关在AJAX基础已经学了这里省略
IP和端口
去看计网
http模块
从这里开始,就是后端基础了,node后端需要借助这个http模块进行
js
const http = require('http')
http.createServer ------ 创建http服务对象
语法: http.createServer( (request, response) => {} )
参数:
- resquest:请求报文内容,包含请求体
- response:响应报文, 对请求的响应信息在这里面进行配置
js
const server = http.createServer( (res, req) => {
// ...
response.end('响应结束')
} )
响应内容中文乱码的解决
在请求头中规定文本类型
js
const server = http.createServer( (res, req) => {
// 设置接受的文本类型
response.setHeader('Content-Type', 'text/html; charset=utf-8')
response.end('响应结束')
} )
server.listen ------ 监听
语法: server.listen( port, callback )
参数:
- post: 端口号
- callback:启动监听服务成功时的回调
http协议默认端口是80, https协议的默认端口是443,http服务开发常用端口有3000、8080、8090、9000等
获取请求体的相关数据
解义 | 获取语法 |
---|---|
method - 请求方法 | request.method |
httpVersion - http协议版本号 | request.httpVersion |
url - 请求路径 | request.url |
url路径 | request('url').parse(request.url).pathname |
url查询字符串, 以此可以获取query参数 | request('url').parse(request.url, true).query |
header - 请求头 | request.headers |
data - 请求体 | request.on('data', (chunk) => {})、request.on('end', ()=>{}) |
获取请求体的流程
js
const url = require('url')
const server = http.createServer( (req, res) => {
// 获取请求方法
let { method } = req
// 解析url
let resUrl = new URL(req.url , ip)
let pathName = resUrl.pathname
let query = res.query
let body = ''
// ...
request.on('data', (chunk) => {
body += chunk
})
request.on('end', () => {
console.log(body)
// 响应
response.end(body)
})
} )
设置http相应报文
作用 | 语法 |
---|---|
code - 设置响应状态码 | response.statusCode |
message - 设置响应状态描述 | response.statusMessage |
header - 响应头信息 | response.setHeader('头名', '头值') |
data - 响应体,即后端返回给前端的前台需要的数据 | response.write(data) response.end('end') |
对接过后端的应该可以很清晰看出来都是些什么作用,所以就直接写示例了
js
const server = http.createServer( (req, res) => {
// ... 根据一些情况进行处理并设置状态码、message、header等信息
if(xxxxx){
response.statusCode == xxxx
response.statusMessage = 'xxxxx'
response.setHeader('Content-Type': ['yyyy', 'qqqq'])
}
// ...
// 设置响应体
response.write(yourData)
// ...
request.on('data', (chunk) => {
body += chunk
})
// ....
response.end()
} )
网页资源加载过程
网页引入外部资源
静态与动态资源
搭建静态资源服务
网页URL的使用
mime类型
媒体类型mime
是一种标准,用来表示文档、文件或者字节流的性质和格式
HTTP服务可以设置响应头Conent-Type
来表示响应体的MIME类型,浏览器会根据该类型决定如何处理资源
常见文件的mime类型
文件类型 | 对应mime类型 |
---|---|
html | text/html |
css | text/css |
js | text/javascript |
png | image/png |
jpg | image/jpeg |
gif | image/gif |
mp4 | vidio/mp4 |
mp3 | audio/mpeg |
json | application/json |
对于未知的资源类型,可以使用application/octet-stream
类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储
乱码问题
headers里面设置字符集编码utf-8
错误处理
对err.code进行switch case
GET 和 POST 的场景以及区别
GET请求使用场景:
- 在地址栏输入url访问
- 点击a标签
- <link>标签引入css
- <script>标签引入js
- <video>和<audio>引入多媒体
- <img>标签引入图片
- <form>标签中的method为get
- AJAX中的get请求
POST请求的情况
- <form>标签中的method为post
- AJAX中的post请求
区别
- 作用:GET请求用来获取数据,POST请求用来提交数据
- 参数位置:GET请求的参数是拼接在
URL
之后,而POST是参数放在请求体data
里 - 安全性:POST请求相对更安全,因为参数不会暴露在url里
- GET请求大小一般限制为2k,POST请求没有大小限制
模块化
类比组件思维,就是为了高内聚低耦合,提高复用性和可维护性,防止命名冲突
在node.js中,导入模块或者文件要使用require()
模块化示例如下:
js
// 暴露模块
// ./test.js
function sendCoursesList(){
// ...
}
// 模块暴露单个数据
modules.exports = sendCoursesList
// ./index.js中导入模块
const sendCoursesList = require('./test.js')
sendCoursesList()
模块暴露对象写法:还是以上面为例
js
// ./test.js
modules.exports = {
sendCoursesList,
fn1,
// ...
fn2: getList()
}
// ./index.js
const test = require('./test.js')
test.getList()
模块暴露变量:下面是例子
js
// ./test.js
exports.fn1 = sendCoursesList
// ./index.js
const test = require('./test.js')
test.fn1()
- modules.export可以暴露任意数据
- 不可以使用
exports = value
的形式暴露数据,模块内部存在module与exports的隐式关系:exports = modules.exports = {}
- 根据上面那条,导入后得到的是一个对象
CommonJS模块化规范
以上的module.exports
、exports
、require
都是CommonJS
规范中的内容,Node.js
的编写要遵从CommonJS
模块化规范,这就像JS和ECMAScript规范一样
有关CommonJS
和ESM
的区别,后面会专门出一篇文章总结,这里占个坑